You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@geode.apache.org by GitBox <gi...@apache.org> on 2021/07/28 19:50:44 UTC

[GitHub] [geode-native] pdxcodemonkey commented on a change in pull request #834: GEODE-9359: Add NetCore SessionState support

pdxcodemonkey commented on a change in pull request #834:
URL: https://github.com/apache/geode-native/pull/834#discussion_r678601117



##########
File path: netcore/NetCore.Session/NetCoreSessionState.cs
##########
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+using Apache.Geode.Client;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apache.Geode.Session
+{
+    public class GeodeSessionStateValue
+    {
+        DateTime _lastAccessTimeUtc;
+        DateTime _expirationTimeUtc = DateTime.MinValue;
+        TimeSpan _spanUntilStale = TimeSpan.Zero;
+        private byte[] _value;
+
+        public GeodeSessionStateValue() { }
+        public GeodeSessionStateValue(byte[] value)
+        {
+            FromByteArray(value);
+        }
+
+        public byte[] Value
+        {
+            get { return _value; }
+            set { _value = value; }
+        }
+        public DateTime LastAccessTimeUtc
+        {
+            get { return _lastAccessTimeUtc; }
+            set { _lastAccessTimeUtc = value; }
+        }
+
+        public DateTime ExpirationTimeUtc
+        {
+            get { return _expirationTimeUtc; }
+            set { _expirationTimeUtc = value; }
+        }
+
+        public TimeSpan SpanUntilStale
+        {
+            get { return _spanUntilStale; }
+            set { _spanUntilStale = value; }
+        }
+
+        public byte[] ToByteArray()
+        {
+            int neededBytes = 3 * sizeof(long) + _value.Length;
+            byte[] byteArray = new byte[neededBytes];
+            int byteIndex = 0;
+
+            // Append LastAccessTimeUtc
+            Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.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 SpanUntilStale
+            Array.Copy(BitConverter.GetBytes(SpanUntilStale.Ticks), 0, byteArray, byteIndex, sizeof(long));
+            byteIndex += sizeof(long);
+
+            // Append the value
+            Array.Copy(_value, 0, byteArray, byteIndex, _value.Length);
+            return byteArray;
+        }
+
+        public void FromByteArray(byte[] data)
+        {
+            int byteIndex = 0;
+
+            // Extract the LastAccessTimeUtc
+            LastAccessTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the ExpirationTimeUtc
+            ExpirationTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the SpanUntilStale
+            SpanUntilStale = TimeSpan.FromTicks(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);
+        }
+    }
+
+    public class GeodeSessionStateCache : GeodeNativeObject, IDistributedCache
+    {
+        private readonly IGeodeCache _cache;
+        private ILogger<GeodeSessionStateCache> _logger;
+        private static Region _region;
+        private string _regionName;
+        private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(initialCount: 1, maxCount: 1);
+
+        public GeodeSessionStateCache(IOptions<GeodeSessionStateCacheOptions> optionsAccessor) {
+
+            var host = optionsAccessor.Value.Host;
+            var port = optionsAccessor.Value.Port;
+            _regionName = optionsAccessor.Value.RegionName;
+
+            _cache = CacheFactory.Create()
+                .SetProperty("log-level", "none")
+                .CreateCache();
+
+            _cache.PoolManager
+                .CreatePoolFactory()
+                .AddLocator(host, port)
+                .CreatePool("pool");
+
+            var regionFactory = _cache.CreateRegionFactory(RegionShortcut.Proxy);
+            _region = regionFactory.CreateRegion(_regionName);
+        }
+
+        // Returns the SessionStateValue for key, or null if key doesn't exist
+        public GeodeSessionStateValue GetValueForKey(string key)
+        {
+            byte[] cacheValue = _region.GetByteArray(key);
+
+            if (cacheValue != null)
+            {
+                return new GeodeSessionStateValue(cacheValue);
+            }
+            else
+                return null;
+        }
+
+        public byte[] Get(string key)
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            Connect();
+
+            // Check for nonexistent key
+            GeodeSessionStateValue 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;
+        }
+
+        public Task<byte[]> GetAsync(string key, CancellationToken token = default(CancellationToken))
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            token.ThrowIfCancellationRequested();
+
+            return Task.Factory.StartNew(() => Get(key), token);
+        }
+
+        public void Refresh(string key)
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            Connect();
+
+            // Check for nonexistent key
+            GeodeSessionStateValue ssValue = GetValueForKey(key);
+            if (ssValue == null)

Review comment:
       More single-line if statements without braces.  Just, no.  Pls add braces.

##########
File path: netcore/NetCore.Session.IntegrationTests/Properties/launchSettings.json
##########
@@ -0,0 +1,8 @@
+{
+  "profiles": {
+    "Apache.Geode.Session.IntegrationTests": {
+      "commandName": "Project",
+      "nativeDebugging": true
+    }
+  }
+}

Review comment:
       Missing newline at EOF.  Where there's one of these, there will probably be others.
   

##########
File path: netcore/NetCore.Session/NetCoreSessionState.cs
##########
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+using Apache.Geode.Client;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apache.Geode.Session
+{
+    public class GeodeSessionStateValue
+    {
+        DateTime _lastAccessTimeUtc;
+        DateTime _expirationTimeUtc = DateTime.MinValue;
+        TimeSpan _spanUntilStale = TimeSpan.Zero;
+        private byte[] _value;
+
+        public GeodeSessionStateValue() { }
+        public GeodeSessionStateValue(byte[] value)
+        {
+            FromByteArray(value);
+        }
+
+        public byte[] Value
+        {
+            get { return _value; }
+            set { _value = value; }
+        }
+        public DateTime LastAccessTimeUtc
+        {
+            get { return _lastAccessTimeUtc; }
+            set { _lastAccessTimeUtc = value; }
+        }
+
+        public DateTime ExpirationTimeUtc
+        {
+            get { return _expirationTimeUtc; }
+            set { _expirationTimeUtc = value; }
+        }
+
+        public TimeSpan SpanUntilStale
+        {
+            get { return _spanUntilStale; }
+            set { _spanUntilStale = value; }
+        }
+
+        public byte[] ToByteArray()
+        {
+            int neededBytes = 3 * sizeof(long) + _value.Length;
+            byte[] byteArray = new byte[neededBytes];
+            int byteIndex = 0;
+
+            // Append LastAccessTimeUtc
+            Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.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 SpanUntilStale
+            Array.Copy(BitConverter.GetBytes(SpanUntilStale.Ticks), 0, byteArray, byteIndex, sizeof(long));
+            byteIndex += sizeof(long);
+
+            // Append the value
+            Array.Copy(_value, 0, byteArray, byteIndex, _value.Length);
+            return byteArray;
+        }
+
+        public void FromByteArray(byte[] data)
+        {
+            int byteIndex = 0;
+
+            // Extract the LastAccessTimeUtc
+            LastAccessTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the ExpirationTimeUtc
+            ExpirationTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the SpanUntilStale
+            SpanUntilStale = TimeSpan.FromTicks(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);
+        }
+    }
+
+    public class GeodeSessionStateCache : GeodeNativeObject, IDistributedCache
+    {
+        private readonly IGeodeCache _cache;
+        private ILogger<GeodeSessionStateCache> _logger;
+        private static Region _region;
+        private string _regionName;
+        private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(initialCount: 1, maxCount: 1);
+
+        public GeodeSessionStateCache(IOptions<GeodeSessionStateCacheOptions> optionsAccessor) {
+
+            var host = optionsAccessor.Value.Host;
+            var port = optionsAccessor.Value.Port;
+            _regionName = optionsAccessor.Value.RegionName;
+
+            _cache = CacheFactory.Create()
+                .SetProperty("log-level", "none")
+                .CreateCache();
+
+            _cache.PoolManager
+                .CreatePoolFactory()
+                .AddLocator(host, port)
+                .CreatePool("pool");
+
+            var regionFactory = _cache.CreateRegionFactory(RegionShortcut.Proxy);
+            _region = regionFactory.CreateRegion(_regionName);
+        }
+
+        // Returns the SessionStateValue for key, or null if key doesn't exist
+        public GeodeSessionStateValue GetValueForKey(string key)
+        {
+            byte[] cacheValue = _region.GetByteArray(key);
+
+            if (cacheValue != null)
+            {
+                return new GeodeSessionStateValue(cacheValue);
+            }
+            else
+                return null;
+        }
+
+        public byte[] Get(string key)
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            Connect();
+
+            // Check for nonexistent key
+            GeodeSessionStateValue 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: " +

Review comment:
       Remove commented code, pls.

##########
File path: netcore/geode-dotnet-core.sln
##########
@@ -7,24 +7,56 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore", "NetCore\NetCore.
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore.Test", "NetCore.Test\NetCore.Test.csproj", "{501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Session", "Session", "{520C96EC-F929-4365-8D78-CC5785419B62}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore.Session", "NetCore.Session\NetCore.Session.csproj", "{B88C58EB-B144-403B-85F7-7A5B45E643E3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore.Session.IntegrationTests", "NetCore.Session.IntegrationTests\NetCore.Session.IntegrationTests.csproj", "{94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
 		Debug|x64 = Debug|x64
+		Release|Any CPU = Release|Any CPU
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Debug|Any CPU.ActiveCfg = Debug|x64
 		{09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Debug|x64.ActiveCfg = Debug|x64
 		{09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Debug|x64.Build.0 = Debug|x64
+		{09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Release|Any CPU.ActiveCfg = Release|x64

Review comment:
       Figuring out how to build that flavor using `dotnet build` is still a to-do item.  I tried just changing the name, and it still didn't build symbols, so there's some kind of secret sauce I have to go figure out.

##########
File path: netcore/geode-dotnet-core.sln
##########
@@ -7,24 +7,56 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore", "NetCore\NetCore.
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore.Test", "NetCore.Test\NetCore.Test.csproj", "{501DEA7E-8985-42A8-8BC9-C073E1B6DFE0}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Session", "Session", "{520C96EC-F929-4365-8D78-CC5785419B62}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore.Session", "NetCore.Session\NetCore.Session.csproj", "{B88C58EB-B144-403B-85F7-7A5B45E643E3}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetCore.Session.IntegrationTests", "NetCore.Session.IntegrationTests\NetCore.Session.IntegrationTests.csproj", "{94D2CD59-A5F3-4504-BF01-0A3B95CE12B5}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
 		Debug|x64 = Debug|x64
+		Release|Any CPU = Release|Any CPU
 		Release|x64 = Release|x64
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{09ABBCE7-B217-43F1-A51B-CC5BDCD8EE98}.Debug|Any CPU.ActiveCfg = Debug|x64

Review comment:
       I don't think we need `Any CPU` configs for any of these projects, let's just get rid of 'em.  Almost certainly you can't build `Apache.Geode.Client` for Any CPU, and it doesn't appear the .sln format lets you keep it on a per-project bases.

##########
File path: netcore/NetCore.Session/NetCoreSessionState.cs
##########
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+using Apache.Geode.Client;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apache.Geode.Session
+{
+    public class GeodeSessionStateValue
+    {
+        DateTime _lastAccessTimeUtc;
+        DateTime _expirationTimeUtc = DateTime.MinValue;
+        TimeSpan _spanUntilStale = TimeSpan.Zero;
+        private byte[] _value;
+
+        public GeodeSessionStateValue() { }
+        public GeodeSessionStateValue(byte[] value)
+        {
+            FromByteArray(value);
+        }
+
+        public byte[] Value

Review comment:
       These are all trivial getters/setters, so all these properties should be auto-implemented a la RegionName, Host, and Port in the options class.

##########
File path: netcore/NetCore.Session/NetCoreSessionState.cs
##########
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+using Apache.Geode.Client;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apache.Geode.Session
+{
+    public class GeodeSessionStateValue
+    {
+        DateTime _lastAccessTimeUtc;
+        DateTime _expirationTimeUtc = DateTime.MinValue;
+        TimeSpan _spanUntilStale = TimeSpan.Zero;
+        private byte[] _value;
+
+        public GeodeSessionStateValue() { }
+        public GeodeSessionStateValue(byte[] value)
+        {
+            FromByteArray(value);
+        }
+
+        public byte[] Value
+        {
+            get { return _value; }
+            set { _value = value; }
+        }
+        public DateTime LastAccessTimeUtc
+        {
+            get { return _lastAccessTimeUtc; }
+            set { _lastAccessTimeUtc = value; }
+        }
+
+        public DateTime ExpirationTimeUtc
+        {
+            get { return _expirationTimeUtc; }
+            set { _expirationTimeUtc = value; }
+        }
+
+        public TimeSpan SpanUntilStale
+        {
+            get { return _spanUntilStale; }
+            set { _spanUntilStale = value; }
+        }
+
+        public byte[] ToByteArray()
+        {
+            int neededBytes = 3 * sizeof(long) + _value.Length;
+            byte[] byteArray = new byte[neededBytes];
+            int byteIndex = 0;
+
+            // Append LastAccessTimeUtc
+            Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.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 SpanUntilStale
+            Array.Copy(BitConverter.GetBytes(SpanUntilStale.Ticks), 0, byteArray, byteIndex, sizeof(long));
+            byteIndex += sizeof(long);
+
+            // Append the value
+            Array.Copy(_value, 0, byteArray, byteIndex, _value.Length);
+            return byteArray;
+        }
+
+        public void FromByteArray(byte[] data)
+        {
+            int byteIndex = 0;
+
+            // Extract the LastAccessTimeUtc
+            LastAccessTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the ExpirationTimeUtc
+            ExpirationTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the SpanUntilStale
+            SpanUntilStale = TimeSpan.FromTicks(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);
+        }
+    }
+
+    public class GeodeSessionStateCache : GeodeNativeObject, IDistributedCache
+    {
+        private readonly IGeodeCache _cache;
+        private ILogger<GeodeSessionStateCache> _logger;
+        private static Region _region;
+        private string _regionName;
+        private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(initialCount: 1, maxCount: 1);
+
+        public GeodeSessionStateCache(IOptions<GeodeSessionStateCacheOptions> optionsAccessor) {
+
+            var host = optionsAccessor.Value.Host;
+            var port = optionsAccessor.Value.Port;
+            _regionName = optionsAccessor.Value.RegionName;
+
+            _cache = CacheFactory.Create()
+                .SetProperty("log-level", "none")

Review comment:
       This is a _great_ suggestion - let's externalize log-level for the session, it'll pay us back later.

##########
File path: netcore/NetCore.Session/GeodeCacheServiceCollectionExtensions.cs
##########
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+ using System;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Apache.Geode.Session
+{
+    public static class GeodeCacheServiceCollectionExtensions
+    {

Review comment:
       Hint - you should be able to run `clang-format` locally on these, using the .clang-format file in `/netcore`.

##########
File path: netcore/NetCore.Session/NetCoreSessionState.cs
##########
@@ -0,0 +1,377 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+using Apache.Geode.Client;
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Apache.Geode.Session
+{
+    public class GeodeSessionStateValue
+    {
+        DateTime _lastAccessTimeUtc;
+        DateTime _expirationTimeUtc = DateTime.MinValue;
+        TimeSpan _spanUntilStale = TimeSpan.Zero;
+        private byte[] _value;
+
+        public GeodeSessionStateValue() { }
+        public GeodeSessionStateValue(byte[] value)
+        {
+            FromByteArray(value);
+        }
+
+        public byte[] Value
+        {
+            get { return _value; }
+            set { _value = value; }
+        }
+        public DateTime LastAccessTimeUtc
+        {
+            get { return _lastAccessTimeUtc; }
+            set { _lastAccessTimeUtc = value; }
+        }
+
+        public DateTime ExpirationTimeUtc
+        {
+            get { return _expirationTimeUtc; }
+            set { _expirationTimeUtc = value; }
+        }
+
+        public TimeSpan SpanUntilStale
+        {
+            get { return _spanUntilStale; }
+            set { _spanUntilStale = value; }
+        }
+
+        public byte[] ToByteArray()
+        {
+            int neededBytes = 3 * sizeof(long) + _value.Length;
+            byte[] byteArray = new byte[neededBytes];
+            int byteIndex = 0;
+
+            // Append LastAccessTimeUtc
+            Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.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 SpanUntilStale
+            Array.Copy(BitConverter.GetBytes(SpanUntilStale.Ticks), 0, byteArray, byteIndex, sizeof(long));
+            byteIndex += sizeof(long);
+
+            // Append the value
+            Array.Copy(_value, 0, byteArray, byteIndex, _value.Length);
+            return byteArray;
+        }
+
+        public void FromByteArray(byte[] data)
+        {
+            int byteIndex = 0;
+
+            // Extract the LastAccessTimeUtc
+            LastAccessTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the ExpirationTimeUtc
+            ExpirationTimeUtc = DateTime.FromBinary(BitConverter.ToInt64(data, byteIndex));
+            byteIndex += sizeof(long);
+
+            // Extract the SpanUntilStale
+            SpanUntilStale = TimeSpan.FromTicks(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);
+        }
+    }
+
+    public class GeodeSessionStateCache : GeodeNativeObject, IDistributedCache
+    {
+        private readonly IGeodeCache _cache;
+        private ILogger<GeodeSessionStateCache> _logger;
+        private static Region _region;
+        private string _regionName;
+        private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(initialCount: 1, maxCount: 1);
+
+        public GeodeSessionStateCache(IOptions<GeodeSessionStateCacheOptions> optionsAccessor) {
+
+            var host = optionsAccessor.Value.Host;
+            var port = optionsAccessor.Value.Port;
+            _regionName = optionsAccessor.Value.RegionName;
+
+            _cache = CacheFactory.Create()
+                .SetProperty("log-level", "none")
+                .CreateCache();
+
+            _cache.PoolManager
+                .CreatePoolFactory()
+                .AddLocator(host, port)
+                .CreatePool("pool");
+
+            var regionFactory = _cache.CreateRegionFactory(RegionShortcut.Proxy);
+            _region = regionFactory.CreateRegion(_regionName);
+        }
+
+        // Returns the SessionStateValue for key, or null if key doesn't exist
+        public GeodeSessionStateValue GetValueForKey(string key)
+        {
+            byte[] cacheValue = _region.GetByteArray(key);
+
+            if (cacheValue != null)
+            {
+                return new GeodeSessionStateValue(cacheValue);
+            }
+            else
+                return null;
+        }
+
+        public byte[] Get(string key)
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            Connect();
+
+            // Check for nonexistent key
+            GeodeSessionStateValue ssValue = GetValueForKey(key);
+            if (ssValue == null)

Review comment:
       OMG can't believe I missed this(!).  Shouldn't `clang-format` or LGTM or something enforce this for us?  Guess we're gonna struggle a little bit until we get the analysis & formatting tools incorporated into CI builds of netcore.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@geode.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org