1 package cache
2
3 import (
4 "encoding/gob"
5 "fmt"
6 "io"
7 "os"
8 "runtime"
9 "sync"
10 "time"
11 )
12
13 type Item struct {
14 Object interface{}
15 Expiration int64
16 }
17
18
19 func (item Item) Expired() bool {
20 if item.Expiration == 0 {
21 return false
22 }
23 return time.Now().UnixNano() > item.Expiration
24 }
25
26 const (
27
28 NoExpiration time.Duration = -1
29
30
31
32 DefaultExpiration time.Duration = 0
33 )
34
35 type Cache struct {
36 *cache
37
38 }
39
40 type cache struct {
41 defaultExpiration time.Duration
42 items map[string]Item
43 mu sync.RWMutex
44 onEvicted func(string, interface{})
45 janitor *janitor
46 }
47
48
49
50
51 func (c *cache) Set(k string, x interface{}, d time.Duration) {
52
53 var e int64
54 if d == DefaultExpiration {
55 d = c.defaultExpiration
56 }
57 if d > 0 {
58 e = time.Now().Add(d).UnixNano()
59 }
60 c.mu.Lock()
61 c.items[k] = Item{
62 Object: x,
63 Expiration: e,
64 }
65
66
67 c.mu.Unlock()
68 }
69
70 func (c *cache) set(k string, x interface{}, d time.Duration) {
71 var e int64
72 if d == DefaultExpiration {
73 d = c.defaultExpiration
74 }
75 if d > 0 {
76 e = time.Now().Add(d).UnixNano()
77 }
78 c.items[k] = Item{
79 Object: x,
80 Expiration: e,
81 }
82 }
83
84
85
86 func (c *cache) SetDefault(k string, x interface{}) {
87 c.Set(k, x, DefaultExpiration)
88 }
89
90
91
92 func (c *cache) Add(k string, x interface{}, d time.Duration) error {
93 c.mu.Lock()
94 _, found := c.get(k)
95 if found {
96 c.mu.Unlock()
97 return fmt.Errorf("Item %s already exists", k)
98 }
99 c.set(k, x, d)
100 c.mu.Unlock()
101 return nil
102 }
103
104
105
106 func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
107 c.mu.Lock()
108 _, found := c.get(k)
109 if !found {
110 c.mu.Unlock()
111 return fmt.Errorf("Item %s doesn't exist", k)
112 }
113 c.set(k, x, d)
114 c.mu.Unlock()
115 return nil
116 }
117
118
119
120 func (c *cache) Get(k string) (interface{}, bool) {
121 c.mu.RLock()
122
123 item, found := c.items[k]
124 if !found {
125 c.mu.RUnlock()
126 return nil, false
127 }
128 if item.Expiration > 0 {
129 if time.Now().UnixNano() > item.Expiration {
130 c.mu.RUnlock()
131 return nil, false
132 }
133 }
134 c.mu.RUnlock()
135 return item.Object, true
136 }
137
138
139
140
141
142 func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {
143 c.mu.RLock()
144
145 item, found := c.items[k]
146 if !found {
147 c.mu.RUnlock()
148 return nil, time.Time{}, false
149 }
150
151 if item.Expiration > 0 {
152 if time.Now().UnixNano() > item.Expiration {
153 c.mu.RUnlock()
154 return nil, time.Time{}, false
155 }
156
157
158 c.mu.RUnlock()
159 return item.Object, time.Unix(0, item.Expiration), true
160 }
161
162
163
164 c.mu.RUnlock()
165 return item.Object, time.Time{}, true
166 }
167
168 func (c *cache) get(k string) (interface{}, bool) {
169 item, found := c.items[k]
170 if !found {
171 return nil, false
172 }
173
174 if item.Expiration > 0 {
175 if time.Now().UnixNano() > item.Expiration {
176 return nil, false
177 }
178 }
179 return item.Object, true
180 }
181
182
183
184
185
186
187 func (c *cache) Increment(k string, n int64) error {
188 c.mu.Lock()
189 v, found := c.items[k]
190 if !found || v.Expired() {
191 c.mu.Unlock()
192 return fmt.Errorf("Item %s not found", k)
193 }
194 switch v.Object.(type) {
195 case int:
196 v.Object = v.Object.(int) + int(n)
197 case int8:
198 v.Object = v.Object.(int8) + int8(n)
199 case int16:
200 v.Object = v.Object.(int16) + int16(n)
201 case int32:
202 v.Object = v.Object.(int32) + int32(n)
203 case int64:
204 v.Object = v.Object.(int64) + n
205 case uint:
206 v.Object = v.Object.(uint) + uint(n)
207 case uintptr:
208 v.Object = v.Object.(uintptr) + uintptr(n)
209 case uint8:
210 v.Object = v.Object.(uint8) + uint8(n)
211 case uint16:
212 v.Object = v.Object.(uint16) + uint16(n)
213 case uint32:
214 v.Object = v.Object.(uint32) + uint32(n)
215 case uint64:
216 v.Object = v.Object.(uint64) + uint64(n)
217 case float32:
218 v.Object = v.Object.(float32) + float32(n)
219 case float64:
220 v.Object = v.Object.(float64) + float64(n)
221 default:
222 c.mu.Unlock()
223 return fmt.Errorf("The value for %s is not an integer", k)
224 }
225 c.items[k] = v
226 c.mu.Unlock()
227 return nil
228 }
229
230
231
232
233
234
235 func (c *cache) IncrementFloat(k string, n float64) error {
236 c.mu.Lock()
237 v, found := c.items[k]
238 if !found || v.Expired() {
239 c.mu.Unlock()
240 return fmt.Errorf("Item %s not found", k)
241 }
242 switch v.Object.(type) {
243 case float32:
244 v.Object = v.Object.(float32) + float32(n)
245 case float64:
246 v.Object = v.Object.(float64) + n
247 default:
248 c.mu.Unlock()
249 return fmt.Errorf("The value for %s does not have type float32 or float64", k)
250 }
251 c.items[k] = v
252 c.mu.Unlock()
253 return nil
254 }
255
256
257
258
259 func (c *cache) IncrementInt(k string, n int) (int, error) {
260 c.mu.Lock()
261 v, found := c.items[k]
262 if !found || v.Expired() {
263 c.mu.Unlock()
264 return 0, fmt.Errorf("Item %s not found", k)
265 }
266 rv, ok := v.Object.(int)
267 if !ok {
268 c.mu.Unlock()
269 return 0, fmt.Errorf("The value for %s is not an int", k)
270 }
271 nv := rv + n
272 v.Object = nv
273 c.items[k] = v
274 c.mu.Unlock()
275 return nv, nil
276 }
277
278
279
280
281 func (c *cache) IncrementInt8(k string, n int8) (int8, error) {
282 c.mu.Lock()
283 v, found := c.items[k]
284 if !found || v.Expired() {
285 c.mu.Unlock()
286 return 0, fmt.Errorf("Item %s not found", k)
287 }
288 rv, ok := v.Object.(int8)
289 if !ok {
290 c.mu.Unlock()
291 return 0, fmt.Errorf("The value for %s is not an int8", k)
292 }
293 nv := rv + n
294 v.Object = nv
295 c.items[k] = v
296 c.mu.Unlock()
297 return nv, nil
298 }
299
300
301
302
303 func (c *cache) IncrementInt16(k string, n int16) (int16, error) {
304 c.mu.Lock()
305 v, found := c.items[k]
306 if !found || v.Expired() {
307 c.mu.Unlock()
308 return 0, fmt.Errorf("Item %s not found", k)
309 }
310 rv, ok := v.Object.(int16)
311 if !ok {
312 c.mu.Unlock()
313 return 0, fmt.Errorf("The value for %s is not an int16", k)
314 }
315 nv := rv + n
316 v.Object = nv
317 c.items[k] = v
318 c.mu.Unlock()
319 return nv, nil
320 }
321
322
323
324
325 func (c *cache) IncrementInt32(k string, n int32) (int32, error) {
326 c.mu.Lock()
327 v, found := c.items[k]
328 if !found || v.Expired() {
329 c.mu.Unlock()
330 return 0, fmt.Errorf("Item %s not found", k)
331 }
332 rv, ok := v.Object.(int32)
333 if !ok {
334 c.mu.Unlock()
335 return 0, fmt.Errorf("The value for %s is not an int32", k)
336 }
337 nv := rv + n
338 v.Object = nv
339 c.items[k] = v
340 c.mu.Unlock()
341 return nv, nil
342 }
343
344
345
346
347 func (c *cache) IncrementInt64(k string, n int64) (int64, error) {
348 c.mu.Lock()
349 v, found := c.items[k]
350 if !found || v.Expired() {
351 c.mu.Unlock()
352 return 0, fmt.Errorf("Item %s not found", k)
353 }
354 rv, ok := v.Object.(int64)
355 if !ok {
356 c.mu.Unlock()
357 return 0, fmt.Errorf("The value for %s is not an int64", k)
358 }
359 nv := rv + n
360 v.Object = nv
361 c.items[k] = v
362 c.mu.Unlock()
363 return nv, nil
364 }
365
366
367
368
369 func (c *cache) IncrementUint(k string, n uint) (uint, error) {
370 c.mu.Lock()
371 v, found := c.items[k]
372 if !found || v.Expired() {
373 c.mu.Unlock()
374 return 0, fmt.Errorf("Item %s not found", k)
375 }
376 rv, ok := v.Object.(uint)
377 if !ok {
378 c.mu.Unlock()
379 return 0, fmt.Errorf("The value for %s is not an uint", k)
380 }
381 nv := rv + n
382 v.Object = nv
383 c.items[k] = v
384 c.mu.Unlock()
385 return nv, nil
386 }
387
388
389
390
391 func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) {
392 c.mu.Lock()
393 v, found := c.items[k]
394 if !found || v.Expired() {
395 c.mu.Unlock()
396 return 0, fmt.Errorf("Item %s not found", k)
397 }
398 rv, ok := v.Object.(uintptr)
399 if !ok {
400 c.mu.Unlock()
401 return 0, fmt.Errorf("The value for %s is not an uintptr", k)
402 }
403 nv := rv + n
404 v.Object = nv
405 c.items[k] = v
406 c.mu.Unlock()
407 return nv, nil
408 }
409
410
411
412
413 func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) {
414 c.mu.Lock()
415 v, found := c.items[k]
416 if !found || v.Expired() {
417 c.mu.Unlock()
418 return 0, fmt.Errorf("Item %s not found", k)
419 }
420 rv, ok := v.Object.(uint8)
421 if !ok {
422 c.mu.Unlock()
423 return 0, fmt.Errorf("The value for %s is not an uint8", k)
424 }
425 nv := rv + n
426 v.Object = nv
427 c.items[k] = v
428 c.mu.Unlock()
429 return nv, nil
430 }
431
432
433
434
435 func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) {
436 c.mu.Lock()
437 v, found := c.items[k]
438 if !found || v.Expired() {
439 c.mu.Unlock()
440 return 0, fmt.Errorf("Item %s not found", k)
441 }
442 rv, ok := v.Object.(uint16)
443 if !ok {
444 c.mu.Unlock()
445 return 0, fmt.Errorf("The value for %s is not an uint16", k)
446 }
447 nv := rv + n
448 v.Object = nv
449 c.items[k] = v
450 c.mu.Unlock()
451 return nv, nil
452 }
453
454
455
456
457 func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) {
458 c.mu.Lock()
459 v, found := c.items[k]
460 if !found || v.Expired() {
461 c.mu.Unlock()
462 return 0, fmt.Errorf("Item %s not found", k)
463 }
464 rv, ok := v.Object.(uint32)
465 if !ok {
466 c.mu.Unlock()
467 return 0, fmt.Errorf("The value for %s is not an uint32", k)
468 }
469 nv := rv + n
470 v.Object = nv
471 c.items[k] = v
472 c.mu.Unlock()
473 return nv, nil
474 }
475
476
477
478
479 func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) {
480 c.mu.Lock()
481 v, found := c.items[k]
482 if !found || v.Expired() {
483 c.mu.Unlock()
484 return 0, fmt.Errorf("Item %s not found", k)
485 }
486 rv, ok := v.Object.(uint64)
487 if !ok {
488 c.mu.Unlock()
489 return 0, fmt.Errorf("The value for %s is not an uint64", k)
490 }
491 nv := rv + n
492 v.Object = nv
493 c.items[k] = v
494 c.mu.Unlock()
495 return nv, nil
496 }
497
498
499
500
501 func (c *cache) IncrementFloat32(k string, n float32) (float32, error) {
502 c.mu.Lock()
503 v, found := c.items[k]
504 if !found || v.Expired() {
505 c.mu.Unlock()
506 return 0, fmt.Errorf("Item %s not found", k)
507 }
508 rv, ok := v.Object.(float32)
509 if !ok {
510 c.mu.Unlock()
511 return 0, fmt.Errorf("The value for %s is not an float32", k)
512 }
513 nv := rv + n
514 v.Object = nv
515 c.items[k] = v
516 c.mu.Unlock()
517 return nv, nil
518 }
519
520
521
522
523 func (c *cache) IncrementFloat64(k string, n float64) (float64, error) {
524 c.mu.Lock()
525 v, found := c.items[k]
526 if !found || v.Expired() {
527 c.mu.Unlock()
528 return 0, fmt.Errorf("Item %s not found", k)
529 }
530 rv, ok := v.Object.(float64)
531 if !ok {
532 c.mu.Unlock()
533 return 0, fmt.Errorf("The value for %s is not an float64", k)
534 }
535 nv := rv + n
536 v.Object = nv
537 c.items[k] = v
538 c.mu.Unlock()
539 return nv, nil
540 }
541
542
543
544
545
546
547 func (c *cache) Decrement(k string, n int64) error {
548
549
550 c.mu.Lock()
551 v, found := c.items[k]
552 if !found || v.Expired() {
553 c.mu.Unlock()
554 return fmt.Errorf("Item not found")
555 }
556 switch v.Object.(type) {
557 case int:
558 v.Object = v.Object.(int) - int(n)
559 case int8:
560 v.Object = v.Object.(int8) - int8(n)
561 case int16:
562 v.Object = v.Object.(int16) - int16(n)
563 case int32:
564 v.Object = v.Object.(int32) - int32(n)
565 case int64:
566 v.Object = v.Object.(int64) - n
567 case uint:
568 v.Object = v.Object.(uint) - uint(n)
569 case uintptr:
570 v.Object = v.Object.(uintptr) - uintptr(n)
571 case uint8:
572 v.Object = v.Object.(uint8) - uint8(n)
573 case uint16:
574 v.Object = v.Object.(uint16) - uint16(n)
575 case uint32:
576 v.Object = v.Object.(uint32) - uint32(n)
577 case uint64:
578 v.Object = v.Object.(uint64) - uint64(n)
579 case float32:
580 v.Object = v.Object.(float32) - float32(n)
581 case float64:
582 v.Object = v.Object.(float64) - float64(n)
583 default:
584 c.mu.Unlock()
585 return fmt.Errorf("The value for %s is not an integer", k)
586 }
587 c.items[k] = v
588 c.mu.Unlock()
589 return nil
590 }
591
592
593
594
595
596
597 func (c *cache) DecrementFloat(k string, n float64) error {
598 c.mu.Lock()
599 v, found := c.items[k]
600 if !found || v.Expired() {
601 c.mu.Unlock()
602 return fmt.Errorf("Item %s not found", k)
603 }
604 switch v.Object.(type) {
605 case float32:
606 v.Object = v.Object.(float32) - float32(n)
607 case float64:
608 v.Object = v.Object.(float64) - n
609 default:
610 c.mu.Unlock()
611 return fmt.Errorf("The value for %s does not have type float32 or float64", k)
612 }
613 c.items[k] = v
614 c.mu.Unlock()
615 return nil
616 }
617
618
619
620
621 func (c *cache) DecrementInt(k string, n int) (int, error) {
622 c.mu.Lock()
623 v, found := c.items[k]
624 if !found || v.Expired() {
625 c.mu.Unlock()
626 return 0, fmt.Errorf("Item %s not found", k)
627 }
628 rv, ok := v.Object.(int)
629 if !ok {
630 c.mu.Unlock()
631 return 0, fmt.Errorf("The value for %s is not an int", k)
632 }
633 nv := rv - n
634 v.Object = nv
635 c.items[k] = v
636 c.mu.Unlock()
637 return nv, nil
638 }
639
640
641
642
643 func (c *cache) DecrementInt8(k string, n int8) (int8, error) {
644 c.mu.Lock()
645 v, found := c.items[k]
646 if !found || v.Expired() {
647 c.mu.Unlock()
648 return 0, fmt.Errorf("Item %s not found", k)
649 }
650 rv, ok := v.Object.(int8)
651 if !ok {
652 c.mu.Unlock()
653 return 0, fmt.Errorf("The value for %s is not an int8", k)
654 }
655 nv := rv - n
656 v.Object = nv
657 c.items[k] = v
658 c.mu.Unlock()
659 return nv, nil
660 }
661
662
663
664
665 func (c *cache) DecrementInt16(k string, n int16) (int16, error) {
666 c.mu.Lock()
667 v, found := c.items[k]
668 if !found || v.Expired() {
669 c.mu.Unlock()
670 return 0, fmt.Errorf("Item %s not found", k)
671 }
672 rv, ok := v.Object.(int16)
673 if !ok {
674 c.mu.Unlock()
675 return 0, fmt.Errorf("The value for %s is not an int16", k)
676 }
677 nv := rv - n
678 v.Object = nv
679 c.items[k] = v
680 c.mu.Unlock()
681 return nv, nil
682 }
683
684
685
686
687 func (c *cache) DecrementInt32(k string, n int32) (int32, error) {
688 c.mu.Lock()
689 v, found := c.items[k]
690 if !found || v.Expired() {
691 c.mu.Unlock()
692 return 0, fmt.Errorf("Item %s not found", k)
693 }
694 rv, ok := v.Object.(int32)
695 if !ok {
696 c.mu.Unlock()
697 return 0, fmt.Errorf("The value for %s is not an int32", k)
698 }
699 nv := rv - n
700 v.Object = nv
701 c.items[k] = v
702 c.mu.Unlock()
703 return nv, nil
704 }
705
706
707
708
709 func (c *cache) DecrementInt64(k string, n int64) (int64, error) {
710 c.mu.Lock()
711 v, found := c.items[k]
712 if !found || v.Expired() {
713 c.mu.Unlock()
714 return 0, fmt.Errorf("Item %s not found", k)
715 }
716 rv, ok := v.Object.(int64)
717 if !ok {
718 c.mu.Unlock()
719 return 0, fmt.Errorf("The value for %s is not an int64", k)
720 }
721 nv := rv - n
722 v.Object = nv
723 c.items[k] = v
724 c.mu.Unlock()
725 return nv, nil
726 }
727
728
729
730
731 func (c *cache) DecrementUint(k string, n uint) (uint, error) {
732 c.mu.Lock()
733 v, found := c.items[k]
734 if !found || v.Expired() {
735 c.mu.Unlock()
736 return 0, fmt.Errorf("Item %s not found", k)
737 }
738 rv, ok := v.Object.(uint)
739 if !ok {
740 c.mu.Unlock()
741 return 0, fmt.Errorf("The value for %s is not an uint", k)
742 }
743 nv := rv - n
744 v.Object = nv
745 c.items[k] = v
746 c.mu.Unlock()
747 return nv, nil
748 }
749
750
751
752
753 func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) {
754 c.mu.Lock()
755 v, found := c.items[k]
756 if !found || v.Expired() {
757 c.mu.Unlock()
758 return 0, fmt.Errorf("Item %s not found", k)
759 }
760 rv, ok := v.Object.(uintptr)
761 if !ok {
762 c.mu.Unlock()
763 return 0, fmt.Errorf("The value for %s is not an uintptr", k)
764 }
765 nv := rv - n
766 v.Object = nv
767 c.items[k] = v
768 c.mu.Unlock()
769 return nv, nil
770 }
771
772
773
774
775 func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) {
776 c.mu.Lock()
777 v, found := c.items[k]
778 if !found || v.Expired() {
779 c.mu.Unlock()
780 return 0, fmt.Errorf("Item %s not found", k)
781 }
782 rv, ok := v.Object.(uint8)
783 if !ok {
784 c.mu.Unlock()
785 return 0, fmt.Errorf("The value for %s is not an uint8", k)
786 }
787 nv := rv - n
788 v.Object = nv
789 c.items[k] = v
790 c.mu.Unlock()
791 return nv, nil
792 }
793
794
795
796
797 func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) {
798 c.mu.Lock()
799 v, found := c.items[k]
800 if !found || v.Expired() {
801 c.mu.Unlock()
802 return 0, fmt.Errorf("Item %s not found", k)
803 }
804 rv, ok := v.Object.(uint16)
805 if !ok {
806 c.mu.Unlock()
807 return 0, fmt.Errorf("The value for %s is not an uint16", k)
808 }
809 nv := rv - n
810 v.Object = nv
811 c.items[k] = v
812 c.mu.Unlock()
813 return nv, nil
814 }
815
816
817
818
819 func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) {
820 c.mu.Lock()
821 v, found := c.items[k]
822 if !found || v.Expired() {
823 c.mu.Unlock()
824 return 0, fmt.Errorf("Item %s not found", k)
825 }
826 rv, ok := v.Object.(uint32)
827 if !ok {
828 c.mu.Unlock()
829 return 0, fmt.Errorf("The value for %s is not an uint32", k)
830 }
831 nv := rv - n
832 v.Object = nv
833 c.items[k] = v
834 c.mu.Unlock()
835 return nv, nil
836 }
837
838
839
840
841 func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) {
842 c.mu.Lock()
843 v, found := c.items[k]
844 if !found || v.Expired() {
845 c.mu.Unlock()
846 return 0, fmt.Errorf("Item %s not found", k)
847 }
848 rv, ok := v.Object.(uint64)
849 if !ok {
850 c.mu.Unlock()
851 return 0, fmt.Errorf("The value for %s is not an uint64", k)
852 }
853 nv := rv - n
854 v.Object = nv
855 c.items[k] = v
856 c.mu.Unlock()
857 return nv, nil
858 }
859
860
861
862
863 func (c *cache) DecrementFloat32(k string, n float32) (float32, error) {
864 c.mu.Lock()
865 v, found := c.items[k]
866 if !found || v.Expired() {
867 c.mu.Unlock()
868 return 0, fmt.Errorf("Item %s not found", k)
869 }
870 rv, ok := v.Object.(float32)
871 if !ok {
872 c.mu.Unlock()
873 return 0, fmt.Errorf("The value for %s is not an float32", k)
874 }
875 nv := rv - n
876 v.Object = nv
877 c.items[k] = v
878 c.mu.Unlock()
879 return nv, nil
880 }
881
882
883
884
885 func (c *cache) DecrementFloat64(k string, n float64) (float64, error) {
886 c.mu.Lock()
887 v, found := c.items[k]
888 if !found || v.Expired() {
889 c.mu.Unlock()
890 return 0, fmt.Errorf("Item %s not found", k)
891 }
892 rv, ok := v.Object.(float64)
893 if !ok {
894 c.mu.Unlock()
895 return 0, fmt.Errorf("The value for %s is not an float64", k)
896 }
897 nv := rv - n
898 v.Object = nv
899 c.items[k] = v
900 c.mu.Unlock()
901 return nv, nil
902 }
903
904
905 func (c *cache) Delete(k string) {
906 c.mu.Lock()
907 v, evicted := c.delete(k)
908 c.mu.Unlock()
909 if evicted {
910 c.onEvicted(k, v)
911 }
912 }
913
914 func (c *cache) delete(k string) (interface{}, bool) {
915 if c.onEvicted != nil {
916 if v, found := c.items[k]; found {
917 delete(c.items, k)
918 return v.Object, true
919 }
920 }
921 delete(c.items, k)
922 return nil, false
923 }
924
925 type keyAndValue struct {
926 key string
927 value interface{}
928 }
929
930
931 func (c *cache) DeleteExpired() {
932 var evictedItems []keyAndValue
933 now := time.Now().UnixNano()
934 c.mu.Lock()
935 for k, v := range c.items {
936
937 if v.Expiration > 0 && now > v.Expiration {
938 ov, evicted := c.delete(k)
939 if evicted {
940 evictedItems = append(evictedItems, keyAndValue{k, ov})
941 }
942 }
943 }
944 c.mu.Unlock()
945 for _, v := range evictedItems {
946 c.onEvicted(v.key, v.value)
947 }
948 }
949
950
951
952
953 func (c *cache) OnEvicted(f func(string, interface{})) {
954 c.mu.Lock()
955 c.onEvicted = f
956 c.mu.Unlock()
957 }
958
959
960
961
962
963 func (c *cache) Save(w io.Writer) (err error) {
964 enc := gob.NewEncoder(w)
965 defer func() {
966 if x := recover(); x != nil {
967 err = fmt.Errorf("Error registering item types with Gob library")
968 }
969 }()
970 c.mu.RLock()
971 defer c.mu.RUnlock()
972 for _, v := range c.items {
973 gob.Register(v.Object)
974 }
975 err = enc.Encode(&c.items)
976 return
977 }
978
979
980
981
982
983
984 func (c *cache) SaveFile(fname string) error {
985 fp, err := os.Create(fname)
986 if err != nil {
987 return err
988 }
989 err = c.Save(fp)
990 if err != nil {
991 fp.Close()
992 return err
993 }
994 return fp.Close()
995 }
996
997
998
999
1000
1001
1002 func (c *cache) Load(r io.Reader) error {
1003 dec := gob.NewDecoder(r)
1004 items := map[string]Item{}
1005 err := dec.Decode(&items)
1006 if err == nil {
1007 c.mu.Lock()
1008 defer c.mu.Unlock()
1009 for k, v := range items {
1010 ov, found := c.items[k]
1011 if !found || ov.Expired() {
1012 c.items[k] = v
1013 }
1014 }
1015 }
1016 return err
1017 }
1018
1019
1020
1021
1022
1023
1024 func (c *cache) LoadFile(fname string) error {
1025 fp, err := os.Open(fname)
1026 if err != nil {
1027 return err
1028 }
1029 err = c.Load(fp)
1030 if err != nil {
1031 fp.Close()
1032 return err
1033 }
1034 return fp.Close()
1035 }
1036
1037
1038 func (c *cache) Items() map[string]Item {
1039 c.mu.RLock()
1040 defer c.mu.RUnlock()
1041 m := make(map[string]Item, len(c.items))
1042 now := time.Now().UnixNano()
1043 for k, v := range c.items {
1044
1045 if v.Expiration > 0 {
1046 if now > v.Expiration {
1047 continue
1048 }
1049 }
1050 m[k] = v
1051 }
1052 return m
1053 }
1054
1055
1056
1057 func (c *cache) ItemCount() int {
1058 c.mu.RLock()
1059 n := len(c.items)
1060 c.mu.RUnlock()
1061 return n
1062 }
1063
1064
1065 func (c *cache) Flush() {
1066 c.mu.Lock()
1067 c.items = map[string]Item{}
1068 c.mu.Unlock()
1069 }
1070
1071 type janitor struct {
1072 Interval time.Duration
1073 stop chan bool
1074 }
1075
1076 func (j *janitor) Run(c *cache) {
1077 ticker := time.NewTicker(j.Interval)
1078 for {
1079 select {
1080 case <-ticker.C:
1081 c.DeleteExpired()
1082 case <-j.stop:
1083 ticker.Stop()
1084 return
1085 }
1086 }
1087 }
1088
1089 func stopJanitor(c *Cache) {
1090 c.janitor.stop <- true
1091 }
1092
1093 func runJanitor(c *cache, ci time.Duration) {
1094 j := &janitor{
1095 Interval: ci,
1096 stop: make(chan bool),
1097 }
1098 c.janitor = j
1099 go j.Run(c)
1100 }
1101
1102 func newCache(de time.Duration, m map[string]Item) *cache {
1103 if de == 0 {
1104 de = -1
1105 }
1106 c := &cache{
1107 defaultExpiration: de,
1108 items: m,
1109 }
1110 return c
1111 }
1112
1113 func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
1114 c := newCache(de, m)
1115
1116
1117
1118
1119
1120 C := &Cache{c}
1121 if ci > 0 {
1122 runJanitor(c, ci)
1123 runtime.SetFinalizer(C, stopJanitor)
1124 }
1125 return C
1126 }
1127
1128
1129
1130
1131
1132
1133 func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
1134 items := make(map[string]Item)
1135 return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
1136 }
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159 func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache {
1160 return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
1161 }
1162
View as plain text