11using Enyim . Caching . Memcached ;
2- using Microsoft . AspNetCore . DataProtection . KeyManagement ;
32using Newtonsoft . Json . Linq ;
4- using System . Data ;
53using System . Diagnostics ;
64using System . Dynamic ;
75using System . Net ;
8- using System . Text . Json ;
6+
97
108namespace 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