1
1
using Enyim . Caching . Memcached ;
2
- using Microsoft . AspNetCore . DataProtection . KeyManagement ;
3
2
using Newtonsoft . Json . Linq ;
4
- using System . Data ;
5
3
using System . Diagnostics ;
6
4
using System . Dynamic ;
7
5
using System . Net ;
8
- using System . Text . Json ;
6
+
9
7
10
8
namespace API
11
9
{
@@ -602,7 +600,7 @@ private bool SubStore(string subKey, string data, TimeSpan validFor, string repo
602
600
603
601
var serializedObj = Utility . JsonSerialize_IgnoreLoopingReference ( obj ) ;
604
602
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 ) ;
606
604
}
607
605
}
608
606
@@ -638,14 +636,30 @@ private void CasRepositoryStore(string key, string repository)
638
636
// Initiate Keys
639
637
List < string > keys = new List < string > ( ) ;
640
638
639
+
640
+
641
+
641
642
try
642
643
{
643
644
// Initiate loop
644
645
bool pending = true ;
645
646
do
646
647
{
648
+
649
+ Log . Instance . Info ( "CasRepositoryStore repository is " + repository ) ;
647
650
// 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
+ }
649
663
650
664
// Check if Cas record exists
651
665
if ( casCache . Result != null && casCache . Result . Count > 0 )
@@ -670,8 +684,7 @@ private void CasRepositoryStore(string key, string repository)
670
684
pending = ! casStore . Result ;
671
685
672
686
}
673
-
674
-
687
+
675
688
} while ( pending ) ;
676
689
677
690
Log . Instance . Info ( "Key [" + key + "] added to Repository [" + repository + "]" ) ;
@@ -684,7 +697,7 @@ private void CasRepositoryStore(string key, string repository)
684
697
}
685
698
finally
686
699
{
687
- sw . Stop ( ) ;
700
+ sw . Stop ( ) ;
688
701
var duration = Utility . StopWatchToSeconds ( sw ) ;
689
702
690
703
@@ -696,17 +709,19 @@ private void CasRepositoryStore(string key, string repository)
696
709
697
710
var serializedObj = Utility . JsonSerialize_IgnoreLoopingReference ( obj ) ;
698
711
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 ) ;
700
713
}
701
714
}
702
715
716
+
717
+
703
718
/// <summary>
704
719
/// Remove all the cached records stored into a Cas Repository
705
720
/// </summary>
706
721
/// <param name="repository"></param>
707
722
public bool CasRepositoryFlush ( string repository )
708
723
{
709
- bool allOk = true ;
724
+ Exception ex = null ;
710
725
// Check if it's enabled first
711
726
if ( ! IsEnabled ( ) )
712
727
{
@@ -729,33 +744,94 @@ public bool CasRepositoryFlush(string repository)
729
744
730
745
// Initiate Keys
731
746
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 ;
741
748
try
742
749
{
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
+ }
744
772
745
773
foreach ( var key in keys )
746
774
{
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 ;
748
824
}
749
825
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
751
827
752
- return check . Cas == 0 ;
753
828
}
754
829
catch ( Exception e )
755
830
{
756
831
Log . Instance . Fatal ( e ) ;
757
832
successTraceFlag = false ;
758
833
return false ;
834
+
759
835
}
760
836
finally
761
837
{
@@ -764,17 +840,15 @@ public bool CasRepositoryFlush(string repository)
764
840
765
841
JObject obj = new JObject
766
842
{
767
- new JProperty ( "repository" , repository )
843
+ new JProperty ( "repository" , repository )
768
844
} ;
769
845
770
846
var serializedObj = Utility . JsonSerialize_IgnoreLoopingReference ( obj ) ;
771
847
772
848
773
849
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 ) ;
775
851
}
776
-
777
-
778
852
}
779
853
780
854
/// <summary>
@@ -923,7 +997,8 @@ private MemCachedD_Value Get(string key)
923
997
successTraceFlag = false ;
924
998
Log . Instance . Fatal ( e ) ;
925
999
}
926
- finally {
1000
+ finally
1001
+ {
927
1002
sw . Stop ( ) ;
928
1003
var duration = Utility . StopWatchToSeconds ( sw ) ;
929
1004
@@ -935,7 +1010,7 @@ private MemCachedD_Value Get(string key)
935
1010
var serializedObj = Utility . JsonSerialize_IgnoreLoopingReference ( obj ) ;
936
1011
937
1012
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 ) ;
939
1014
}
940
1015
941
1016
return value ;
@@ -1033,7 +1108,7 @@ private bool Remove(string key)
1033
1108
1034
1109
1035
1110
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 ) ;
1037
1112
}
1038
1113
}
1039
1114
@@ -1060,12 +1135,13 @@ public void FlushAll()
1060
1135
{
1061
1136
successTraceFlag = false ;
1062
1137
Log . Instance . Fatal ( e ) ;
1063
- } finally
1138
+ }
1139
+ finally
1064
1140
{
1065
1141
sw . Stop ( ) ;
1066
1142
var duration = Utility . StopWatchToSeconds ( sw ) ;
1067
1143
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 ) ;
1069
1145
}
1070
1146
}
1071
1147
@@ -1101,9 +1177,9 @@ public ServerStats GetStats()
1101
1177
sw . Stop ( ) ;
1102
1178
var duration = Utility . StopWatchToSeconds ( sw ) ;
1103
1179
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 ) ;
1105
1181
}
1106
-
1182
+
1107
1183
}
1108
1184
1109
1185
/// <summary>
@@ -1123,7 +1199,7 @@ private static MemCachedD_Value SetValue(dynamic data, DateTime expiresAt, TimeS
1123
1199
{
1124
1200
return value ;
1125
1201
}
1126
-
1202
+
1127
1203
try
1128
1204
{
1129
1205
value . datetime = DateTime . Now ;
0 commit comments