[ 
https://issues.apache.org/jira/browse/GEODE-9359?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17388915#comment-17388915
 ] 

ASF GitHub Bot commented on GEODE-9359:
---------------------------------------

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



##########
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:
       Formatting is not consistent with the .NET Core client sources.

##########
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;

Review comment:
       formatting

##########
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:
       What about `RelWithDebInfo`?

##########
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;

Review comment:
       Use `var` throughout rather than redundantly specifying the type. 
Consistency with the client source is key.

##########
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:
       Why not allow logging level to be configured?

##########
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:
       Can you mix `Any CPU` with client assemblies that rely on native 
libraries compiled for specific CPU types?

##########
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:
       Always use braces.

##########
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)
+                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: " +

Review comment:
       Delete commented out code.

##########
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

Review comment:
       These comments do provide any meaningful information over the source 
below it. If the intent is to show some form of segmentation in the 
serialization then perhaps making them full blown methods.
   ```C#
   byteIndex += AppendLastAccessTimeUtc(byteArray, byteIndex);
   byteIndex += AppendExpirationTimeUtc(byteArray, byteIndex);
   ...
   
   int AppendLastAccessTimeUtc(byte[] bytes, int offset) {
     Array.Copy(BitConverter.GetBytes(LastAccessTimeUtc.Ticks), 0, bytes, 
offset, sizeof(long));
     return sizeof(long);
   }
   ```

##########
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)
+                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());
+            }
+        }
+
+        public Task RefreshAsync(string key, CancellationToken token = 
default(CancellationToken))
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            token.ThrowIfCancellationRequested();
+
+            return Task.Factory.StartNew(() => Refresh(key), token);
+        }
+
+        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);
+        }
+
+        public Task RemoveAsync(string key, CancellationToken token = 
default(CancellationToken))
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            token.ThrowIfCancellationRequested();
+
+            return Task.Factory.StartNew(() => Remove(key), token);
+        }
+
+        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();
+
+            GeodeSessionStateValue ssValue = new GeodeSessionStateValue();
+            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;
+        }
+
+        public Task SetAsync(string key, byte[] value, 
DistributedCacheEntryOptions options, CancellationToken token = 
default(CancellationToken))
+        {
+            if (key == null)
+            {
+                throw new ArgumentNullException(nameof(key));
+            }
+
+            token.ThrowIfCancellationRequested();
+
+            return Task.Factory.StartNew(() => Set(key, value, options), 
token);
+        }
+
+        private void Connect()
+        {
+            if (_region != null)
+            {
+                return;
+            }
+
+            _connectLock.Wait();
+            try
+            {
+                using var 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();
+            }
+        }
+
+        protected override void DestroyContainedObject()
+        {
+            _region?.Dispose();
+            _region = null;
+        }
+    }
+}

Review comment:
       New line at end of source files.




-- 
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-unsubscr...@geode.apache.org

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


> add net-core-session to geode-native
> ------------------------------------
>
>                 Key: GEODE-9359
>                 URL: https://issues.apache.org/jira/browse/GEODE-9359
>             Project: Geode
>          Issue Type: New Feature
>          Components: native client
>            Reporter: Ernest Burghardt
>            Priority: Major
>              Labels: pull-request-available
>
> net-core-session shall be added to the top level of geode-native repo and 
> will produce a separate binary that will be publishable to NuGet
> https://docs.microsoft.com/en-us/nuget/create-packages/package-authoring-best-practices



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to