netramesh

Форк
0
1161 строка · 30.3 Кб
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
// Returns true if the item has expired.
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
	// For use with functions that take an expiration time.
28
	NoExpiration time.Duration = -1
29
	// For use with functions that take an expiration time. Equivalent to
30
	// passing in the same expiration duration as was given to New() or
31
	// NewFrom() when the cache was created (e.g. 5 minutes.)
32
	DefaultExpiration time.Duration = 0
33
)
34

35
type Cache struct {
36
	*cache
37
	// If this is confusing, see the comment at the bottom of New()
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
// Add an item to the cache, replacing any existing item. If the duration is 0
49
// (DefaultExpiration), the cache's default expiration time is used. If it is -1
50
// (NoExpiration), the item never expires.
51
func (c *cache) Set(k string, x interface{}, d time.Duration) {
52
	// "Inlining" of set
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
	// TODO: Calls to mu.Unlock are currently not deferred because defer
66
	// adds ~200 ns (as of go1.)
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
// Add an item to the cache, replacing any existing item, using the default
85
// expiration.
86
func (c *cache) SetDefault(k string, x interface{}) {
87
	c.Set(k, x, DefaultExpiration)
88
}
89

90
// Add an item to the cache only if an item doesn't already exist for the given
91
// key, or if the existing item has expired. Returns an error otherwise.
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
// Set a new value for the cache key only if it already exists, and the existing
105
// item hasn't expired. Returns an error otherwise.
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
// Get an item from the cache. Returns the item or nil, and a bool indicating
119
// whether the key was found.
120
func (c *cache) Get(k string) (interface{}, bool) {
121
	c.mu.RLock()
122
	// "Inlining" of get and Expired
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
// GetWithExpiration returns an item and its expiration time from the cache.
139
// It returns the item or nil, the expiration time if one is set (if the item
140
// never expires a zero value for time.Time is returned), and a bool indicating
141
// whether the key was found.
142
func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {
143
	c.mu.RLock()
144
	// "Inlining" of get and Expired
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
		// Return the item and the expiration time
158
		c.mu.RUnlock()
159
		return item.Object, time.Unix(0, item.Expiration), true
160
	}
161

162
	// If expiration <= 0 (i.e. no expiration time set) then return the item
163
	// and a zeroed time.Time
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
	// "Inlining" of Expired
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
// Increment an item of type int, int8, int16, int32, int64, uintptr, uint,
183
// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
184
// item's value is not an integer, if it was not found, or if it is not
185
// possible to increment it by n. To retrieve the incremented value, use one
186
// of the specialized methods, e.g. IncrementInt64.
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
// Increment an item of type float32 or float64 by n. Returns an error if the
231
// item's value is not floating point, if it was not found, or if it is not
232
// possible to increment it by n. Pass a negative number to decrement the
233
// value. To retrieve the incremented value, use one of the specialized methods,
234
// e.g. IncrementFloat64.
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
// Increment an item of type int by n. Returns an error if the item's value is
257
// not an int, or if it was not found. If there is no error, the incremented
258
// value is returned.
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
// Increment an item of type int8 by n. Returns an error if the item's value is
279
// not an int8, or if it was not found. If there is no error, the incremented
280
// value is returned.
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
// Increment an item of type int16 by n. Returns an error if the item's value is
301
// not an int16, or if it was not found. If there is no error, the incremented
302
// value is returned.
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
// Increment an item of type int32 by n. Returns an error if the item's value is
323
// not an int32, or if it was not found. If there is no error, the incremented
324
// value is returned.
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
// Increment an item of type int64 by n. Returns an error if the item's value is
345
// not an int64, or if it was not found. If there is no error, the incremented
346
// value is returned.
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
// Increment an item of type uint by n. Returns an error if the item's value is
367
// not an uint, or if it was not found. If there is no error, the incremented
368
// value is returned.
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
// Increment an item of type uintptr by n. Returns an error if the item's value
389
// is not an uintptr, or if it was not found. If there is no error, the
390
// incremented value is returned.
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
// Increment an item of type uint8 by n. Returns an error if the item's value
411
// is not an uint8, or if it was not found. If there is no error, the
412
// incremented value is returned.
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
// Increment an item of type uint16 by n. Returns an error if the item's value
433
// is not an uint16, or if it was not found. If there is no error, the
434
// incremented value is returned.
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
// Increment an item of type uint32 by n. Returns an error if the item's value
455
// is not an uint32, or if it was not found. If there is no error, the
456
// incremented value is returned.
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
// Increment an item of type uint64 by n. Returns an error if the item's value
477
// is not an uint64, or if it was not found. If there is no error, the
478
// incremented value is returned.
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
// Increment an item of type float32 by n. Returns an error if the item's value
499
// is not an float32, or if it was not found. If there is no error, the
500
// incremented value is returned.
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
// Increment an item of type float64 by n. Returns an error if the item's value
521
// is not an float64, or if it was not found. If there is no error, the
522
// incremented value is returned.
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
// Decrement an item of type int, int8, int16, int32, int64, uintptr, uint,
543
// uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
544
// item's value is not an integer, if it was not found, or if it is not
545
// possible to decrement it by n. To retrieve the decremented value, use one
546
// of the specialized methods, e.g. DecrementInt64.
547
func (c *cache) Decrement(k string, n int64) error {
548
	// TODO: Implement Increment and Decrement more cleanly.
549
	// (Cannot do Increment(k, n*-1) for uints.)
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
// Decrement an item of type float32 or float64 by n. Returns an error if the
593
// item's value is not floating point, if it was not found, or if it is not
594
// possible to decrement it by n. Pass a negative number to decrement the
595
// value. To retrieve the decremented value, use one of the specialized methods,
596
// e.g. DecrementFloat64.
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
// Decrement an item of type int by n. Returns an error if the item's value is
619
// not an int, or if it was not found. If there is no error, the decremented
620
// value is returned.
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
// Decrement an item of type int8 by n. Returns an error if the item's value is
641
// not an int8, or if it was not found. If there is no error, the decremented
642
// value is returned.
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
// Decrement an item of type int16 by n. Returns an error if the item's value is
663
// not an int16, or if it was not found. If there is no error, the decremented
664
// value is returned.
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
// Decrement an item of type int32 by n. Returns an error if the item's value is
685
// not an int32, or if it was not found. If there is no error, the decremented
686
// value is returned.
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
// Decrement an item of type int64 by n. Returns an error if the item's value is
707
// not an int64, or if it was not found. If there is no error, the decremented
708
// value is returned.
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
// Decrement an item of type uint by n. Returns an error if the item's value is
729
// not an uint, or if it was not found. If there is no error, the decremented
730
// value is returned.
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
// Decrement an item of type uintptr by n. Returns an error if the item's value
751
// is not an uintptr, or if it was not found. If there is no error, the
752
// decremented value is returned.
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
// Decrement an item of type uint8 by n. Returns an error if the item's value is
773
// not an uint8, or if it was not found. If there is no error, the decremented
774
// value is returned.
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
// Decrement an item of type uint16 by n. Returns an error if the item's value
795
// is not an uint16, or if it was not found. If there is no error, the
796
// decremented value is returned.
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
// Decrement an item of type uint32 by n. Returns an error if the item's value
817
// is not an uint32, or if it was not found. If there is no error, the
818
// decremented value is returned.
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
// Decrement an item of type uint64 by n. Returns an error if the item's value
839
// is not an uint64, or if it was not found. If there is no error, the
840
// decremented value is returned.
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
// Decrement an item of type float32 by n. Returns an error if the item's value
861
// is not an float32, or if it was not found. If there is no error, the
862
// decremented value is returned.
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
// Decrement an item of type float64 by n. Returns an error if the item's value
883
// is not an float64, or if it was not found. If there is no error, the
884
// decremented value is returned.
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
// Delete an item from the cache. Does nothing if the key is not in the cache.
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
// Delete all expired items from the cache.
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
		// "Inlining" of expired
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
// Sets an (optional) function that is called with the key and value when an
951
// item is evicted from the cache. (Including when it is deleted manually, but
952
// not when it is overwritten.) Set to nil to disable.
953
func (c *cache) OnEvicted(f func(string, interface{})) {
954
	c.mu.Lock()
955
	c.onEvicted = f
956
	c.mu.Unlock()
957
}
958

959
// Write the cache's items (using Gob) to an io.Writer.
960
//
961
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
962
// documentation for NewFrom().)
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
// Save the cache's items to the given filename, creating the file if it
980
// doesn't exist, and overwriting it if it does.
981
//
982
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
983
// documentation for NewFrom().)
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
// Add (Gob-serialized) cache items from an io.Reader, excluding any items with
998
// keys that already exist (and haven't expired) in the current cache.
999
//
1000
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
1001
// documentation for NewFrom().)
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
// Load and add cache items from the given filename, excluding any items with
1020
// keys that already exist in the current cache.
1021
//
1022
// NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
1023
// documentation for NewFrom().)
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
// Copies all unexpired items in the cache into a new map and returns it.
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
		// "Inlining" of Expired
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
// Returns the number of items in the cache. This may include items that have
1056
// expired, but have not yet been cleaned up.
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
// Delete all items from the cache.
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
	// This trick ensures that the janitor goroutine (which--granted it
1116
	// was enabled--is running DeleteExpired on c forever) does not keep
1117
	// the returned C object from being garbage collected. When it is
1118
	// garbage collected, the finalizer stops the janitor goroutine, after
1119
	// which c can be collected.
1120
	C := &Cache{c}
1121
	if ci > 0 {
1122
		runJanitor(c, ci)
1123
		runtime.SetFinalizer(C, stopJanitor)
1124
	}
1125
	return C
1126
}
1127

1128
// Return a new cache with a given default expiration duration and cleanup
1129
// interval. If the expiration duration is less than one (or NoExpiration),
1130
// the items in the cache never expire (by default), and must be deleted
1131
// manually. If the cleanup interval is less than one, expired items are not
1132
// deleted from the cache before calling c.DeleteExpired().
1133
func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
1134
	items := make(map[string]Item)
1135
	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
1136
}
1137

1138
// Return a new cache with a given default expiration duration and cleanup
1139
// interval. If the expiration duration is less than one (or NoExpiration),
1140
// the items in the cache never expire (by default), and must be deleted
1141
// manually. If the cleanup interval is less than one, expired items are not
1142
// deleted from the cache before calling c.DeleteExpired().
1143
//
1144
// NewFrom() also accepts an items map which will serve as the underlying map
1145
// for the cache. This is useful for starting from a deserialized cache
1146
// (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g.
1147
// make(map[string]Item, 500) to improve startup performance when the cache
1148
// is expected to reach a certain minimum size.
1149
//
1150
// Only the cache's methods synchronize access to this map, so it is not
1151
// recommended to keep any references to the map around after creating a cache.
1152
// If need be, the map can be accessed at a later point using c.Items() (subject
1153
// to the same caveat.)
1154
//
1155
// Note regarding serialization: When using e.g. gob, make sure to
1156
// gob.Register() the individual types stored in the cache before encoding a
1157
// map retrieved with c.Items(), and to register those same types before
1158
// decoding a blob containing an items map.
1159
func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache {
1160
	return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
1161
}
1162

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.