@@ -13,39 +13,127 @@ public class MemoryCacheRedisServer : RedisServer
1313 public MemoryCacheRedisServer ( EndPoint endpoint = null , TextWriter output = null ) : base ( endpoint , 1 , output )
1414 => CreateNewCache ( ) ;
1515
16- private MemoryCache _cache ;
16+ private MemoryCache _cache2 ;
1717
1818 private void CreateNewCache ( )
1919 {
20- var old = _cache ;
21- _cache = new MemoryCache ( GetType ( ) . Name ) ;
20+ var old = _cache2 ;
21+ _cache2 = new MemoryCache ( GetType ( ) . Name ) ;
2222 old ? . Dispose ( ) ;
2323 }
2424
2525 protected override void Dispose ( bool disposing )
2626 {
27- if ( disposing ) _cache . Dispose ( ) ;
27+ if ( disposing ) _cache2 . Dispose ( ) ;
2828 base . Dispose ( disposing ) ;
2929 }
3030
31- protected override long Dbsize ( int database ) => _cache . GetCount ( ) ;
31+ protected override long Dbsize ( int database ) => _cache2 . GetCount ( ) ;
32+
33+ private readonly struct ExpiringValue ( object value , DateTime absoluteExpiration )
34+ {
35+ public readonly object Value = value ;
36+ public readonly DateTime AbsoluteExpiration = absoluteExpiration ;
37+ }
38+
39+ private enum ExpectedType
40+ {
41+ Any = 0 ,
42+ Stack ,
43+ Set ,
44+ List ,
45+ }
46+ private object Get ( in RedisKey key , ExpectedType expectedType )
47+ {
48+ var val = _cache2 [ key ] ;
49+ switch ( val )
50+ {
51+ case null :
52+ return null ;
53+ case ExpiringValue ev :
54+ if ( ev . AbsoluteExpiration <= Now )
55+ {
56+ _cache2 . Remove ( key ) ;
57+ return null ;
58+ }
59+ return Validate ( ev . Value , expectedType ) ;
60+ default :
61+ return Validate ( val , expectedType ) ;
62+ }
63+ static object Validate ( object value , ExpectedType expectedType )
64+ {
65+ return value switch
66+ {
67+ null => value ,
68+ HashSet < RedisValue > set when expectedType is ExpectedType . Set or ExpectedType . Any => value ,
69+ HashSet < RedisValue > => Throw ( ) ,
70+ Stack < RedisValue > stack when expectedType is ExpectedType . List or ExpectedType . Any => value ,
71+ Stack < RedisValue > => Throw ( ) ,
72+ _ when expectedType is ExpectedType . Stack or ExpectedType . Any => value ,
73+ _ => Throw ( ) ,
74+ } ;
75+
76+ static object Throw ( ) => throw new WrongTypeException ( ) ;
77+ }
78+ }
79+ protected override TimeSpan ? Ttl ( int database , in RedisKey key )
80+ {
81+ var val = _cache2 [ key ] ;
82+ switch ( val )
83+ {
84+ case null :
85+ return null ;
86+ case ExpiringValue ev :
87+ var delta = ev . AbsoluteExpiration - Now ;
88+ if ( delta <= TimeSpan . Zero )
89+ {
90+ _cache2 . Remove ( key ) ;
91+ return null ;
92+ }
93+ return delta ;
94+ default :
95+ return TimeSpan . MaxValue ;
96+ }
97+ }
98+
99+ protected override bool Expire ( int database , in RedisKey key , TimeSpan timeout )
100+ {
101+ var val = Get ( key , ExpectedType . Any ) ;
102+ if ( val is not null )
103+ {
104+ _cache2 [ key ] = new ExpiringValue ( val , Now + timeout ) ;
105+ return true ;
106+ }
107+
108+ return false ;
109+ }
110+
32111 protected override RedisValue Get ( int database , in RedisKey key )
33- => RedisValue . Unbox ( _cache [ key ] ) ;
112+ {
113+ var val = Get ( key , ExpectedType . Stack ) ;
114+ return RedisValue . Unbox ( val ) ;
115+ }
116+
34117 protected override void Set ( int database , in RedisKey key , in RedisValue value )
35- => _cache [ key ] = value . Box ( ) ;
118+ => _cache2 [ key ] = value . Box ( ) ;
36119 protected override bool Del ( int database , in RedisKey key )
37- => _cache . Remove ( key ) != null ;
120+ => _cache2 . Remove ( key ) != null ;
38121 protected override void Flushdb ( int database )
39122 => CreateNewCache ( ) ;
40123
124+ private DateTime Now => DateTime . UtcNow ;
41125 protected override bool Exists ( int database , in RedisKey key )
42- => _cache . Contains ( key ) ;
126+ {
127+ var val = Get ( key , ExpectedType . Any ) ;
128+ return val != null && ! ( val is ExpiringValue ev && ev . AbsoluteExpiration <= Now ) ;
129+ }
43130
44131 protected override IEnumerable < RedisKey > Keys ( int database , in RedisKey pattern ) => GetKeysCore ( pattern ) ;
45132 private IEnumerable < RedisKey > GetKeysCore ( RedisKey pattern )
46133 {
47- foreach ( var pair in _cache )
134+ foreach ( var pair in _cache2 )
48135 {
136+ if ( pair . Value is ExpiringValue ev && ev . AbsoluteExpiration <= Now ) continue ;
49137 if ( IsMatch ( pattern , pair . Key ) ) yield return pair . Key ;
50138 }
51139 }
@@ -60,7 +148,7 @@ protected override bool Srem(int database, in RedisKey key, in RedisValue value)
60148 var set = GetSet ( key , false ) ;
61149 if ( set != null && set . Remove ( value ) )
62150 {
63- if ( set . Count == 0 ) _cache . Remove ( key ) ;
151+ if ( set . Count == 0 ) _cache2 . Remove ( key ) ;
64152 return true ;
65153 }
66154 return false ;
@@ -70,11 +158,11 @@ protected override long Scard(int database, in RedisKey key)
70158
71159 private HashSet < RedisValue > GetSet ( RedisKey key , bool create )
72160 {
73- var set = ( HashSet < RedisValue > ) _cache [ key ] ;
161+ var set = ( HashSet < RedisValue > ) Get ( key , ExpectedType . Set ) ;
74162 if ( set == null && create )
75163 {
76164 set = new HashSet < RedisValue > ( ) ;
77- _cache [ key ] = set ;
165+ _cache2 [ key ] = set ;
78166 }
79167 return set ;
80168 }
@@ -86,7 +174,7 @@ protected override RedisValue Spop(int database, in RedisKey key)
86174
87175 var result = set . First ( ) ;
88176 set . Remove ( result ) ;
89- if ( set . Count == 0 ) _cache . Remove ( key ) ;
177+ if ( set . Count == 0 ) _cache2 . Remove ( key ) ;
90178 return result ;
91179 }
92180
@@ -102,7 +190,7 @@ protected override RedisValue Lpop(int database, in RedisKey key)
102190 if ( stack == null ) return RedisValue . Null ;
103191
104192 var val = stack . Pop ( ) ;
105- if ( stack . Count == 0 ) _cache . Remove ( key ) ;
193+ if ( stack . Count == 0 ) _cache2 . Remove ( key ) ;
106194 return val ;
107195 }
108196
@@ -130,13 +218,13 @@ protected override void LRange(int database, in RedisKey key, long start, Span<T
130218 }
131219 }
132220
133- private Stack < RedisValue > GetStack ( RedisKey key , bool create )
221+ private Stack < RedisValue > GetStack ( in RedisKey key , bool create )
134222 {
135- var stack = ( Stack < RedisValue > ) _cache [ key ] ;
223+ var stack = ( Stack < RedisValue > ) Get ( key , ExpectedType . Stack ) ;
136224 if ( stack == null && create )
137225 {
138226 stack = new Stack < RedisValue > ( ) ;
139- _cache [ key ] = stack ;
227+ _cache2 [ key ] = stack ;
140228 }
141229 return stack ;
142230 }
0 commit comments