Skip to content

Commit 4ea1aca

Browse files
committed
6.1.21 release
- [BUG FIX] Added cache storage of the key GET_WITH_CAS_TIMEOF_EXCEPTION key to store the datetime value of when the GetWithCas exception occurred. - [BUG FIX] Fixes for session to not be expired and System.ArgumentOutOfRangeException when calling GetWithCas.
1 parent 773584b commit 4ea1aca

File tree

5 files changed

+115
-58
lines changed

5 files changed

+115
-58
lines changed

src/API.Library/API.Library.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212
<PackageId>API.Library</PackageId>
1313
<Product>API Library</Product>
1414
<Copyright>Central Statistics Office, Ireland</Copyright>
15-
<Version>6.1.18</Version>
15+
<Version>6.1.21</Version>
1616
<Authors>Central Statistics Office, Ireland</Authors>
1717
<SignAssembly>False</SignAssembly>
1818
<RepositoryUrl>https://github.com/CSOIreland/Server-API-Library</RepositoryUrl>
1919
<PackageReleaseNotes>
20-
- [BUG FIX] upgrading Microsoft.Data.SqlClient to 5.1.4 as 5.1.1 is deprecated
20+
- [BUG FIX] Added cache storage of the key GET_WITH_CAS_TIMEOF_EXCEPTION key to store the datetime value of when the GetWithCas exception occurred.
21+
- [BUG FIX] Fixes for session to not be expired and System.ArgumentOutOfRangeException when calling GetWithCas.
2122
</PackageReleaseNotes>
2223
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
2324
<RestoreLockedMode>true</RestoreLockedMode>

src/API.Library/Entities/ADO.cs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,12 +269,6 @@ public void ExecuteNonQueryProcedure(string procedureName, List<ADO_inputParams>
269269
Log.Instance.Fatal("No SQL Server Connection available");
270270
return;
271271
}
272-
// Check that the transaction exists
273-
if (!CheckTransaction())
274-
{
275-
Log.Instance.Fatal("No transaction found for ExecuteNonQueryProcedure");
276-
throw new Exception("Unable to execute action");
277-
}
278272

279273
// Initiate Stopwatch
280274
Stopwatch sw = new Stopwatch();

src/API.Library/Entities/API.JSONRPC.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ public async Task ProcessRequest(HttpContext httpContext, CancellationTokenSourc
9898
performanceThread.Start();
9999
}
100100
result = GetResult(httpContext, JSONRPC_Request,trace, sessionCookie);
101-
//result.sessionCookie always null unless set it to the sessionCookie from the request
102-
result.sessionCookie = sessionCookie;
103101
break;
104102
case true: //Windows Authentication
105103
if (API_PERFORMANCE_ENABLED)
@@ -138,18 +136,12 @@ public async Task ProcessRequest(HttpContext httpContext, CancellationTokenSourc
138136
// Set the Session Cookie if requested
139137
if (!string.IsNullOrEmpty(SessionCookieName) && result.sessionCookie != null && result.sessionCookie.Name.Equals(SessionCookieName))
140138
{
141-
// No expiry time allowed in the future
142-
if (result.sessionCookie.Expires > DateTime.Now)
143-
{
144-
result.sessionCookie.Expires = default;
145-
}
146139
var cookieOptions = new CookieOptions
147140
{
148141
Secure = true,
149142
HttpOnly = true,
150143
Domain = null,
151144
SameSite = SameSiteMode.Strict,
152-
Expires = result.sessionCookie.Expires
153145
};
154146

155147
// Add the cookie to the response cookie collection

src/API.Library/Entities/API.RESTful.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,18 +140,12 @@ public async Task ProcessRequest(HttpContext httpContext, CancellationTokenSourc
140140
// Set the Session Cookie if requested
141141
if (!string.IsNullOrEmpty(SessionCookieName) && result.sessionCookie != null && result.sessionCookie.Name.Equals(SessionCookieName))
142142
{
143-
// No expiry time allowed in the future
144-
if (result.sessionCookie.Expires > DateTime.Now)
145-
{
146-
result.sessionCookie.Expires = default;
147-
}
148143
var cookieOptions = new CookieOptions
149144
{
150145
Secure = true,
151146
HttpOnly = true,
152147
Domain = null,
153-
SameSite = SameSiteMode.Strict,
154-
Expires = result.sessionCookie.Expires
148+
SameSite = SameSiteMode.Strict
155149
};
156150

157151
// Add the cookie to the response cookie collection

src/API.Library/Entities/MemCacheD.cs

Lines changed: 111 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
using Enyim.Caching.Memcached;
2-
using Microsoft.AspNetCore.DataProtection.KeyManagement;
32
using Newtonsoft.Json.Linq;
4-
using System.Data;
53
using System.Diagnostics;
64
using System.Dynamic;
75
using System.Net;
8-
using System.Text.Json;
6+
97

108
namespace API
119
{
@@ -602,7 +600,7 @@ private bool SubStore(string subKey, string data, TimeSpan validFor, string repo
602600

603601
var serializedObj = Utility.JsonSerialize_IgnoreLoopingReference(obj);
604602
Log.Instance.Info("Memcache SubStore Execution Time (s): " + duration + " Object:" + serializedObj);
605-
CacheTrace.PopulateCacheTrace(serializedObj,traceStart, Utility.StopWatchToSeconds(sw), "SubStore", successTraceFlag, cacheTraceCompressLength, null);
603+
CacheTrace.PopulateCacheTrace(serializedObj, traceStart, Utility.StopWatchToSeconds(sw), "SubStore", successTraceFlag, cacheTraceCompressLength, null);
606604
}
607605
}
608606

@@ -638,14 +636,30 @@ private void CasRepositoryStore(string key, string repository)
638636
// Initiate Keys
639637
List<string> keys = new List<string>();
640638

639+
640+
641+
641642
try
642643
{
643644
// Initiate loop
644645
bool pending = true;
645646
do
646647
{
648+
649+
Log.Instance.Info("CasRepositoryStore repository is " + repository);
647650
// Get list of Keys by Cas per Repository
648-
CasResult<List<string>> casCache = ApiServicesHelper.MemcachedClient.GetWithCas<List<string>>(repository);
651+
CasResult<List<string>> casCache = new();
652+
try
653+
{
654+
casCache = ApiServicesHelper.MemcachedClient.GetWithCas<List<string>>(repository);
655+
}
656+
catch
657+
{
658+
// Silent catching (see https://github.com/cnblogs/EnyimMemcachedCore/issues/211)
659+
660+
// Store the time of exception in the Cache
661+
ApiServicesHelper.MemcachedClient.Store(StoreMode.Set, "GET_WITH_CAS_TIME_OF_EXCEPTION", DateTime.Now.ToString());
662+
}
649663

650664
// Check if Cas record exists
651665
if (casCache.Result != null && casCache.Result.Count > 0)
@@ -670,8 +684,7 @@ private void CasRepositoryStore(string key, string repository)
670684
pending = !casStore.Result;
671685

672686
}
673-
674-
687+
675688
} while (pending);
676689

677690
Log.Instance.Info("Key [" + key + "] added to Repository [" + repository + "]");
@@ -684,7 +697,7 @@ private void CasRepositoryStore(string key, string repository)
684697
}
685698
finally
686699
{
687-
sw.Stop();
700+
sw.Stop();
688701
var duration = Utility.StopWatchToSeconds(sw);
689702

690703

@@ -696,17 +709,19 @@ private void CasRepositoryStore(string key, string repository)
696709

697710
var serializedObj = Utility.JsonSerialize_IgnoreLoopingReference(obj);
698711
Log.Instance.Info("Memcache CasRepositoryStore Execution Time (s): " + duration + " Cas Repository:" + serializedObj);
699-
CacheTrace.PopulateCacheTrace(serializedObj,traceStart, Utility.StopWatchToSeconds(sw), "CasRepositoryStore",successTraceFlag,cacheTraceCompressLength,null);
712+
CacheTrace.PopulateCacheTrace(serializedObj, traceStart, Utility.StopWatchToSeconds(sw), "CasRepositoryStore", successTraceFlag, cacheTraceCompressLength, null);
700713
}
701714
}
702715

716+
717+
703718
/// <summary>
704719
/// Remove all the cached records stored into a Cas Repository
705720
/// </summary>
706721
/// <param name="repository"></param>
707722
public bool CasRepositoryFlush(string repository)
708723
{
709-
bool allOk = true;
724+
Exception ex = null;
710725
// Check if it's enabled first
711726
if (!IsEnabled())
712727
{
@@ -729,33 +744,94 @@ public bool CasRepositoryFlush(string repository)
729744

730745
// Initiate Keys
731746
List<string> keys = new List<string>();
732-
733-
//Get list of Keys by Cas per Repository
734-
CasResult<List<string>> casCache = ApiServicesHelper.MemcachedClient.GetWithCas<List<string>>(repository);
735-
// Check if Cas record exists
736-
if (casCache.Result != null && casCache.Result.Count > 0)
737-
{
738-
// Get the list of Keys
739-
keys = casCache.Result;
740-
}
747+
int keyCount = 0;
741748
try
742749
{
743-
ApiServicesHelper.MemcachedClient.Remove(repository);
750+
Log.Instance.Info("CasRepositoryFlush repository is " + repository);
751+
752+
CasResult<List<string>> casCache = new();
753+
//Get list of Keys by Cas per Repository
754+
try
755+
{
756+
casCache = ApiServicesHelper.MemcachedClient.GetWithCas<List<string>>(repository);
757+
}
758+
catch
759+
{
760+
// Silent catching (see https://github.com/cnblogs/EnyimMemcachedCore/issues/211)
761+
762+
// Store the time of exception in the Cache
763+
ApiServicesHelper.MemcachedClient.Store(StoreMode.Set, "GET_WITH_CAS_TIME_OF_EXCEPTION", DateTime.Now.ToString());
764+
}
765+
// Check if Cas record exists
766+
if (casCache.Result != null && casCache.Result.Count > 0)
767+
{
768+
// Get the list of Keys
769+
keys = casCache.Result;
770+
keyCount = keys.Count;
771+
}
744772

745773
foreach (var key in keys)
746774
{
747-
ApiServicesHelper.MemcachedClient.Remove(key);
775+
try
776+
{
777+
778+
if (!ApiServicesHelper.MemcachedClient.Remove(key))
779+
{
780+
//This will happen if the CAS contains an expired/removed key
781+
//Make sure that it has really been removed
782+
if (ApiServicesHelper.MemcachedClient.TryGet(key, out casCache))
783+
successTraceFlag = false;
784+
785+
}
786+
}
787+
catch (Exception e)
788+
{
789+
ex = e;
790+
successTraceFlag = false;
791+
Log.Instance.Error(e);
792+
Log.Instance.Error("Failed to remove key " + key + " in repository " + repository);
793+
794+
}
795+
796+
}
797+
798+
799+
if (successTraceFlag)
800+
{
801+
var checkData = new CasResult<List<string>>();
802+
try
803+
{
804+
checkData = ApiServicesHelper.MemcachedClient.GetWithCas<List<string>>(repository);
805+
806+
}
807+
catch
808+
{
809+
// Silent catching (see https://github.com/cnblogs/EnyimMemcachedCore/issues/211)
810+
811+
// Store the time of exception in the Cache
812+
ApiServicesHelper.MemcachedClient.Store(StoreMode.Set, "GET_WITH_CAS_TIME_OF_EXCEPTION", DateTime.Now.ToString());
813+
}
814+
if (checkData.Equals(null)) return true;
815+
if (checkData.Result == null) return true;
816+
817+
//For the slight possibility that something may have sneaked into the CAS between the gathering of keys and their disposal
818+
if (keyCount >= checkData.Result.Count)
819+
{
820+
ApiServicesHelper.MemcachedClient.Remove(repository);
821+
return true;
822+
}
823+
else return false;
748824
}
749825

750-
var check = ApiServicesHelper.MemcachedClient.GetWithCas<List<string>>(repository);
826+
else throw new Exception("Error clearing CAS repository " + repository, ex); //CAS flush was not reliable
751827

752-
return check.Cas == 0;
753828
}
754829
catch (Exception e)
755830
{
756831
Log.Instance.Fatal(e);
757832
successTraceFlag = false;
758833
return false;
834+
759835
}
760836
finally
761837
{
@@ -764,17 +840,15 @@ public bool CasRepositoryFlush(string repository)
764840

765841
JObject obj = new JObject
766842
{
767-
new JProperty("repository",repository)
843+
new JProperty("repository",repository)
768844
};
769845

770846
var serializedObj = Utility.JsonSerialize_IgnoreLoopingReference(obj);
771847

772848

773849
Log.Instance.Info("Memcache CasRepositoryFlush Execution Time (s): " + duration + " Repository:" + serializedObj);
774-
CacheTrace.PopulateCacheTrace(serializedObj,traceStart, duration, "CasRepositoryFlush", successTraceFlag, null,null);
850+
CacheTrace.PopulateCacheTrace(serializedObj, traceStart, duration, "CasRepositoryFlush", successTraceFlag, null, null);
775851
}
776-
777-
778852
}
779853

780854
/// <summary>
@@ -923,7 +997,8 @@ private MemCachedD_Value Get(string key)
923997
successTraceFlag = false;
924998
Log.Instance.Fatal(e);
925999
}
926-
finally{
1000+
finally
1001+
{
9271002
sw.Stop();
9281003
var duration = Utility.StopWatchToSeconds(sw);
9291004

@@ -935,7 +1010,7 @@ private MemCachedD_Value Get(string key)
9351010
var serializedObj = Utility.JsonSerialize_IgnoreLoopingReference(obj);
9361011

9371012
Log.Instance.Info("Memcache get Execution Time (s): " + duration + " Key : " + serializedObj);
938-
CacheTrace.PopulateCacheTrace(serializedObj,traceStart, duration, "GET",successTraceFlag, cacheTraceCompressLength, traceExpiresAt);
1013+
CacheTrace.PopulateCacheTrace(serializedObj, traceStart, duration, "GET", successTraceFlag, cacheTraceCompressLength, traceExpiresAt);
9391014
}
9401015

9411016
return value;
@@ -1033,7 +1108,7 @@ private bool Remove(string key)
10331108

10341109

10351110
Log.Instance.Info("Memcache remove Execution Time (s): " + duration + " Key : " + serializedObj);
1036-
CacheTrace.PopulateCacheTrace(serializedObj,traceStart, duration, "REMOVE", successTraceFlag, cacheTraceCompressLength,null);
1111+
CacheTrace.PopulateCacheTrace(serializedObj, traceStart, duration, "REMOVE", successTraceFlag, cacheTraceCompressLength, null);
10371112
}
10381113
}
10391114

@@ -1060,12 +1135,13 @@ public void FlushAll()
10601135
{
10611136
successTraceFlag = false;
10621137
Log.Instance.Fatal(e);
1063-
}finally
1138+
}
1139+
finally
10641140
{
10651141
sw.Stop();
10661142
var duration = Utility.StopWatchToSeconds(sw);
10671143
Log.Instance.Info("Memcache flush all Execution Time (s): " + duration);
1068-
CacheTrace.PopulateCacheTrace(null,traceStart, duration, "FLUSH", successTraceFlag,cacheTraceCompressLength,null);
1144+
CacheTrace.PopulateCacheTrace(null, traceStart, duration, "FLUSH", successTraceFlag, cacheTraceCompressLength, null);
10691145
}
10701146
}
10711147

@@ -1101,9 +1177,9 @@ public ServerStats GetStats()
11011177
sw.Stop();
11021178
var duration = Utility.StopWatchToSeconds(sw);
11031179
Log.Instance.Info("Memcache get stats Execution Time (s): " + duration);
1104-
CacheTrace.PopulateCacheTrace(null,traceStart, duration, "GETSTATS", successTraceFlag,null,null);
1180+
CacheTrace.PopulateCacheTrace(null, traceStart, duration, "GETSTATS", successTraceFlag, null, null);
11051181
}
1106-
1182+
11071183
}
11081184

11091185
/// <summary>
@@ -1123,7 +1199,7 @@ private static MemCachedD_Value SetValue(dynamic data, DateTime expiresAt, TimeS
11231199
{
11241200
return value;
11251201
}
1126-
1202+
11271203
try
11281204
{
11291205
value.datetime = DateTime.Now;

0 commit comments

Comments
 (0)