1 module hunt.cache.Cache;
2 
3 import hunt.cache.adapter;
4 import hunt.cache.CacheOptions;
5 import hunt.cache.Defined;
6 import hunt.cache.Nullable;
7 import hunt.logging.ConsoleLogger;
8 
9 import std.algorithm;
10 import std.array;
11 import std.conv : to;
12 import std.range;
13 
14 final class Cache
15 {
16     this(MemoryAdapter memoryAdapter) {
17         this(memoryAdapter, new CacheOptions());
18     }
19 
20     this(Object adapterObject, CacheOptions option, MemoryAdapter memoryAdapter = null)
21     {
22         version(HUNT_DEBUG) infof("Creating cache: [%s]", option);
23         _option = option;
24         auto className = typeid(adapterObject);
25 
26         if (memoryAdapter !is null && typeid(memoryAdapter) != className)
27         {
28             _memoryAdapter = memoryAdapter;
29             _l2enabled = true;
30         }
31         
32         if(className == typeid(MemoryAdapter))
33         {
34             _memoryAdapter = cast(MemoryAdapter)adapterObject;
35             _type = CACHE_ADAPTER.MEMORY;
36             return;
37         }
38 
39         if(className == typeid(RedisAdapter))
40         {
41             _redisAdapter = cast(RedisAdapter)adapterObject;
42             _type = CACHE_ADAPTER.REDIS;
43             return;
44         }
45         
46         if(className == typeid(RedisClusterAdapter))
47         {
48             _redisClusterAdapter = cast(RedisClusterAdapter)adapterObject;
49             _type = CACHE_ADAPTER.REDIS_CLUSTER;
50             return;
51         }
52 
53         // version(WITH_HUNT_MEMCACHE)
54         // { 
55         //     if(className == typeid(MemcacheAdapter))
56         //     {
57         //         _memcacheAdapter = cast(MemcacheAdapter)(adapterObject);
58         //         _type = CACHE_ADAPTER.MEMCACHE_ADAPTER;
59         //         return;
60         //     }
61         // }
62         
63         version(WITH_HUNT_ROCKSDB)
64         {
65             if(className == typeid(RocksdbAdapter))
66             {    
67                 _rocksdbAdapter = cast(RocksdbAdapter)(adapterObject);
68                 _type = CACHE_ADAPTER.ROCKSDB;
69                 return;
70             }
71         }
72     }
73 
74     
75 
76     Nullable!V get(V = string) (string key)
77     {
78         switch(_type)
79         {
80             case CACHE_ADAPTER.MEMORY:
81                 return get!(MemoryAdapter, V)(key);
82             
83             case CACHE_ADAPTER.REDIS:
84                 return get!(RedisAdapter, V)(key);
85             
86             case CACHE_ADAPTER.REDIS_CLUSTER:
87                 return get!(RedisClusterAdapter, V)(key);
88 
89             // version(WITH_HUNT_MEMCACHE)
90             // {
91             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
92             //     return get!(MemcacheAdapter, V)(key);
93             // }
94 
95             version(WITH_HUNT_ROCKSDB)
96             {
97             case CACHE_ADAPTER.ROCKSDB:
98                 return get!(RocksdbAdapter, V)(key);
99             }
100             
101             default:
102                 return get!(MemoryAdapter, V)(key);
103         }
104     }
105 
106     private Nullable!V get(A, V) (string key)
107     {
108         if(!_option.prefix.empty())
109             key = _option.prefix ~ key;
110 
111         version(HUNT_CACHE_DEBUG) trace("key: ", key);
112 
113         synchronized(this)
114         {
115             if (_l2enabled)
116             {
117                 auto v1 = _memoryAdapter.get!V(key);
118                 if(!v1.isNull)
119                     return v1;
120             }
121 
122             auto v2 = cacheAdapter!A().get!V(key);
123             if(v2.isNull)
124                 return v2;
125 
126             if (_l2enabled)
127             {
128                 _memoryAdapter.set!V(key, v2.origin);
129             }
130 
131             return v2;
132         }
133     }
134 
135 
136     Nullable!V[string] get(V = string) (string[] keys)
137     {
138         switch(_type)
139         {
140             case CACHE_ADAPTER.MEMORY:
141                 return get!(MemoryAdapter, V)(keys);
142 
143             case CACHE_ADAPTER.REDIS:
144                 return get!(RedisAdapter, V)(keys);
145 
146             case CACHE_ADAPTER.REDIS_CLUSTER:
147                 return get!(RedisClusterAdapter, V)(keys);
148 
149             // version(WITH_HUNT_MEMCACHE)
150             // {
151             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
152             //     return get!(MemcacheAdapter, V)(keys);
153             // }
154 
155             version(WITH_HUNT_ROCKSDB)
156             {
157             case CACHE_ADAPTER.ROCKSDB:
158                 return get!(RocksdbAdapter, V)(keys);
159             }
160             
161             default:
162                 return get!(MemoryAdapter, V)(keys);
163         }
164     }
165 
166     private Nullable!V[string] get(A, V) (string[] keys)
167     {
168         if(!_option.prefix.empty()) {
169             keys = keys.map!(k => _option.prefix ~ k)();
170         }
171 
172         synchronized(this)
173         {
174             Nullable!V[string] mapv;
175             foreach(k ; keys)
176             {
177                 mapv[k] = get!(A, V)(k);
178             }
179 
180             return mapv;
181         }
182     }
183 
184     bool hasKey(string key)
185     {
186         switch(_type)
187         {
188             case CACHE_ADAPTER.MEMORY:
189                 return hasKey!MemoryAdapter(key);
190 
191             case CACHE_ADAPTER.REDIS:
192                 return hasKey!RedisAdapter(key);
193 
194             case CACHE_ADAPTER.REDIS_CLUSTER:
195                 return hasKey!RedisClusterAdapter(key);
196 
197             // version(WITH_HUNT_MEMCACHE)
198             // {
199             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
200             //     return hasKey!MemcacheAdapter(key);
201             // }
202             version(WITH_HUNT_ROCKSDB)
203             {
204             case CACHE_ADAPTER.ROCKSDB:
205                 return hasKey!RocksdbAdapter(key);
206             }
207             default:
208                 return hasKey!MemoryAdapter(key);
209         }
210     }
211 
212     bool hasKey(A)(string key)
213     {
214         if(!_option.prefix.empty())
215             key = _option.prefix ~ key;
216 
217         synchronized(this)
218         {
219             return cacheAdapter!A().hasKey(key);
220         }
221     }
222 
223 
224     void set(V) (string key, V v, uint expired = 0)
225     {
226         switch(_type)
227         {
228             case CACHE_ADAPTER.MEMORY:
229                 return set!(MemoryAdapter, V)(key, v, expired);
230             
231             case CACHE_ADAPTER.REDIS:
232                 return set!(RedisAdapter, V)(key, v, expired);
233             
234             case CACHE_ADAPTER.REDIS_CLUSTER:
235                 return set!(RedisClusterAdapter, V)(key, v, expired);
236 
237             // version(WITH_HUNT_MEMCACHE)
238             // {
239             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
240             //     return set!(MemcacheAdapter, V)(key, v, expired);
241             // }
242 
243             version(WITH_HUNT_ROCKSDB)
244             {
245             case CACHE_ADAPTER.ROCKSDB:
246                 return set!(RocksdbAdapter, V)(key, v, expired);
247             }
248 
249             default:
250                 return set!(MemoryAdapter, V)(key, v, expired);
251         }
252     }
253 
254     private void set(A, V) (string key, V v, uint expired = 0)
255     {
256         if(!_option.prefix.empty())
257             key = _option.prefix ~ key;
258 
259         version(HUNT_CACHE_DEBUG) trace("key: ", key);
260 
261         synchronized(this)
262         {
263             cacheAdapter!A().set!V(key, v, expired);
264 
265             if (_l2enabled)
266             {
267                 _memoryAdapter.set!V(key, v, expired);
268             }
269         }
270     }
271 
272     bool setIfAbsent(V) (string key,  V v)
273     {
274         if(!_option.prefix.empty())
275             key = _option.prefix ~ key;
276 
277         synchronized(this)
278         {
279             if(cacheAdapter!A().setIfAbsent!V(key, v))
280             {
281                 if (_l2enabled)
282                 {
283                     _memoryAdapter.set!V(key, v);
284                 }
285 
286                 return true;
287             }
288         }
289 
290         return false;
291     }
292 
293     void set(V) (V[string] maps, uint expired = 0)
294     {
295         switch(_type)
296         {
297             case CACHE_ADAPTER.MEMORY:
298                 return set!(MemoryAdapter, V)(maps, expired);
299 
300             case CACHE_ADAPTER.REDIS:
301                 return set!(RedisAdapter, V)(maps, expired);
302 
303             case CACHE_ADAPTER.REDIS_CLUSTER:
304                 return set!(RedisClusterAdapter, V)(maps, expired);
305 
306             case CACHE_ADAPTER.MEMCACHE_ADAPTER:
307                 return set!(MemcacheAdapter, V)(maps, expired);
308             case CACHE_ADAPTER.ROCKSDB:
309                 return set!(RocksdbAdapter, V)(maps, expired);
310             default:
311                 return set!(MemoryAdapter, V)(maps, expired);
312         }
313     }
314 
315     private void set(A, V) (V[string] maps, uint expired = 0)
316     {
317         synchronized(this)
318         {
319             cacheAdapter!A().set!V(maps, expired);
320             if (_l2enabled)
321             {
322                     _memoryAdapter.set!V(maps, expired);
323             }
324         }
325     }
326 
327     bool remove(string key)
328     {
329         switch(_type)
330         {
331             case CACHE_ADAPTER.MEMORY:
332                 return remove!MemoryAdapter(key);
333 
334             case CACHE_ADAPTER.REDIS:
335                 return remove!RedisAdapter(key);
336 
337             case CACHE_ADAPTER.REDIS_CLUSTER:
338                 return remove!RedisClusterAdapter(key);
339 
340             // version(WITH_HUNT_MEMCACHE)
341             // {
342             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
343             //     return remove!MemcacheAdapter(key);
344             // }
345             version(WITH_HUNT_ROCKSDB)
346             {
347             case CACHE_ADAPTER.ROCKSDB:
348                 return remove!RocksdbAdapter(key);
349             }
350             default:
351                 return remove!MemoryAdapter(key);
352         }
353     }
354 
355     private bool remove(A)(string key)
356     {
357         if(!_option.prefix.empty())
358             key = _option.prefix ~ key;
359 
360         synchronized(this)
361         {
362             auto ret = cacheAdapter!A().remove(key);
363             if (_l2enabled)
364             {
365                 _memoryAdapter.remove(key);
366             }
367             return ret;
368         }
369     }
370 
371     void remove(string[] keys)
372     {
373         switch(_type)
374         {
375             case CACHE_ADAPTER.MEMORY:
376                 remove!MemoryAdapter(keys);
377                 break;
378 
379             case CACHE_ADAPTER.REDIS:
380                 remove!RedisAdapter(keys);
381                 break;
382 
383             case CACHE_ADAPTER.REDIS_CLUSTER:
384                 remove!RedisClusterAdapter(keys);
385                 break;
386 
387             // version(WITH_HUNT_MEMCACHE)
388             // {
389             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
390             //     remove!MemcacheAdapter(keys);
391             //     break;
392             // }
393 
394             version(WITH_HUNT_ROCKSDB)
395             {
396             case CACHE_ADAPTER.ROCKSDB:
397                 remove!RocksdbAdapter(keys);
398                 break;
399             }
400 
401             default:
402                 remove!MemoryAdapter(keys);
403         }
404     }
405 
406     private void remove(A)(string[] keys)
407     {
408         if(!_option.prefix.empty()) {
409             keys = keys.map!(k => _option.prefix ~ k)().array();
410         }
411 
412         synchronized(this)
413         {
414              cacheAdapter!A().remove(keys);
415             if (_l2enabled)
416             {
417                 _memoryAdapter.remove(keys);
418             }
419         }
420     }
421 
422     void clear()
423     {
424         switch(_type)
425         {
426             case CACHE_ADAPTER.MEMORY:
427                 clear!MemoryAdapter();
428                 break;
429             
430             case CACHE_ADAPTER.REDIS:
431                 clear!RedisAdapter();
432                 break;
433 
434             case CACHE_ADAPTER.REDIS_CLUSTER:
435                 clear!RedisClusterAdapter();
436                 break;
437 
438             // version(WITH_HUNT_MEMCACHE)
439             // {
440             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
441             //     clear!MemcacheAdapter();
442             //     break;
443             // }
444 
445             version(WITH_HUNT_ROCKSDB)
446             {
447             case CACHE_ADAPTER.ROCKSDB:
448                 clear!RocksdbAdapter();
449                 break;
450             }
451             
452             default:
453                 clear!MemoryAdapter();
454         }
455     }
456 
457     private void clear(A)()
458     {
459         synchronized(this)
460         {
461              cacheAdapter!A().clear();
462 
463             if (_l2enabled)
464             {
465                 _memoryAdapter.clear();
466             }
467         }
468     }
469 
470     private A cacheAdapter(A)()
471     {
472         switch(_type)
473         {
474             case CACHE_ADAPTER.MEMORY:
475                 return cast(A)_memoryAdapter;
476 
477             case CACHE_ADAPTER.REDIS:
478                 return cast(A)_redisAdapter;
479 
480             // version(WITH_HUNT_MEMCACHE)
481             // {
482             // case CACHE_ADAPTER.MEMCACHE_ADAPTER:
483             //     return cast(A)_memcacheAdapter;
484             // }
485             version(WITH_HUNT_ROCKSDB)
486             {
487             case CACHE_ADAPTER.ROCKSDB:
488                 return cast(A)_rocksdbAdapter;
489             }
490             default:
491                 return cast(A)_memoryAdapter;
492         }
493     }
494 
495     private
496     {
497         bool _l2enabled = false;
498 
499         MemoryAdapter _memoryAdapter;
500         RedisAdapter _redisAdapter;
501         RedisClusterAdapter _redisClusterAdapter;
502         // version(WITH_HUNT_MEMCACHE) MemcacheAdapter _memcacheAdapter;
503         version(WITH_HUNT_ROCKSDB) RocksdbAdapter _rocksdbAdapter;
504 
505         CacheOptions _option;
506 
507         CACHE_ADAPTER _type;
508     }
509 }