Skip to content

Commit fa1c90b

Browse files
authored
Merge pull request #5 from jftuga/bugfix/use-time-duration
use time.Duration and create GoNoUpdate()
2 parents ce9811c + 96c4321 commit fa1c90b

File tree

5 files changed

+108
-60
lines changed

5 files changed

+108
-60
lines changed

Diff for: README.md

+9-6
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ package main
1616
import (
1717
"fmt"
1818
"time"
19-
2019
"github.com/jftuga/TtlMap"
2120
)
2221

2322
func main() {
24-
maxTTL := 4 // a key's time to live in seconds
25-
startSize := 3 // initial number of items in map
26-
pruneInterval := 1 // search for expired items every 'pruneInterval' seconds
27-
refreshLastAccessOnGet := true // update item's 'lastAccessTime' on a .Get()
23+
maxTTL := time.Duration(time.Second * 4) // a key's time to live in seconds
24+
startSize := 3 // initial number of items in map
25+
pruneInterval := time.Duration(time.Second * 1) // search for expired items every 'pruneInterval' seconds
26+
refreshLastAccessOnGet := true // update item's 'lastAccessTime' on a .Get()
2827
t := TtlMap.New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
2928
defer t.Close()
3029

@@ -42,11 +41,12 @@ func main() {
4241

4342
sleepTime := maxTTL + pruneInterval
4443
fmt.Printf("Sleeping %v seconds, items should be 'nil' after this time\n", sleepTime)
45-
time.Sleep(time.Second * time.Duration(sleepTime))
44+
time.Sleep(sleepTime)
4645
fmt.Printf("[%9s] %v\n", "myString", t.Get("myString"))
4746
fmt.Printf("[%9s] %v\n", "int_array", t.Get("int_array"))
4847
fmt.Println("TtlMap length:", t.Len())
4948
}
49+
5050
```
5151

5252
Output:
@@ -66,9 +66,12 @@ TtlMap length: 0
6666

6767
## API functions
6868
* `New`: initialize a `TtlMap`
69+
* `Close`: this stops the goroutine that checks for expired items; use with `defer`
6970
* `Len`: return the number of items in the map
7071
* `Put`: add a key/value
7172
* `Get`: get the current value of the given key; return `nil` if the key is not found in the map
73+
* `GetNoUpdate`: same as `Get`, but do not update the `lastAccess` expiration time
74+
* * * This ignores the `refreshLastAccessOnGet` parameter
7275
* `All`: returns a *copy* of all items in the map
7376
* `Delete`: delete an item; return `true` if the item was deleted, `false` if the item was not found in the map
7477
* `Clear`: remove all items from the map

Diff for: example/example.go

+10-8
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ type User struct {
2121
}
2222

2323
func main() {
24-
maxTTL := 4 // time in seconds
25-
startSize := 3 // initial number of items in map
26-
pruneInterval := 1 // search for expired items every 'pruneInterval' seconds
27-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
24+
maxTTL := time.Duration(time.Second * 4) // time in seconds
25+
startSize := 3 // initial number of items in map
26+
pruneInterval := time.Duration(time.Second * 1) // search for expired items every 'pruneInterval' seconds
27+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
2828
t := TtlMap.New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
2929
defer t.Close()
3030

@@ -75,7 +75,7 @@ func main() {
7575
fmt.Println()
7676
fmt.Printf("Sleeping %v seconds, items should be removed after this time, except for the '%v' key\n", sleepTime, dontExpireKey)
7777
fmt.Println()
78-
time.Sleep(time.Second * time.Duration(sleepTime))
78+
time.Sleep(sleepTime)
7979

8080
// these items have expired and therefore should be nil, except for 'dontExpireKey'
8181
fmt.Printf("[%9s] %v\n", "string", t.Get("string"))
@@ -94,7 +94,7 @@ func main() {
9494
if t.Get("int") == nil {
9595
fmt.Println("[int] is nil")
9696
}
97-
fmt.Println("TtlMap length:", t.Len())
97+
fmt.Println("TtlMap length:", t.Len(), " (should equal 1)")
9898
fmt.Println()
9999

100100
fmt.Println()
@@ -104,14 +104,16 @@ func main() {
104104
fmt.Printf("Manually deleting '%v' key again; should NOT be successful this time\n", dontExpireKey)
105105
success = t.Delete(TtlMap.CustomKeyType(dontExpireKey))
106106
fmt.Printf(" successful? %v\n", success)
107-
fmt.Println("TtlMap length:", t.Len())
107+
fmt.Println("TtlMap length:", t.Len(), " (should equal 0)")
108108
fmt.Println()
109109

110110
fmt.Println("Adding 2 items and then running Clear()")
111111
t.Put("string", "a b c")
112112
t.Put("int", 3)
113113
fmt.Println("TtlMap length:", t.Len())
114-
fmt.Println("running Clear()")
114+
115+
fmt.Println()
116+
fmt.Println("Running Clear()")
115117
t.Clear()
116118
fmt.Println("TtlMap length:", t.Len())
117119
fmt.Println()

Diff for: example/small/small.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88
)
99

1010
func main() {
11-
maxTTL := 4 // a key's time to live in seconds
12-
startSize := 3 // initial number of items in map
13-
pruneInterval := 1 // search for expired items every 'pruneInterval' seconds
14-
refreshLastAccessOnGet := true // update item's 'lastAccessTime' on a .Get()
11+
maxTTL := time.Duration(time.Second * 4) // a key's time to live in seconds
12+
startSize := 3 // initial number of items in map
13+
pruneInterval := time.Duration(time.Second * 1) // search for expired items every 'pruneInterval' seconds
14+
refreshLastAccessOnGet := true // update item's 'lastAccessTime' on a .Get()
1515
t := TtlMap.New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
1616
defer t.Close()
1717

@@ -29,7 +29,7 @@ func main() {
2929

3030
sleepTime := maxTTL + pruneInterval
3131
fmt.Printf("Sleeping %v seconds, items should be 'nil' after this time\n", sleepTime)
32-
time.Sleep(time.Second * time.Duration(sleepTime))
32+
time.Sleep(sleepTime)
3333
fmt.Printf("[%9s] %v\n", "myString", t.Get("myString"))
3434
fmt.Printf("[%9s] %v\n", "int_array", t.Get("int_array"))
3535
fmt.Println("TtlMap length:", t.Len())

Diff for: ttlMap.go

+16-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import (
3232
"time"
3333
)
3434

35-
const version string = "1.3.0"
35+
const version string = "1.4.0"
3636

3737
type CustomKeyType string
3838

@@ -48,28 +48,30 @@ type TtlMap struct {
4848
stop chan bool
4949
}
5050

51-
func New(maxTTL int, ln int, pruneInterval int, refreshLastAccessOnGet bool) (m *TtlMap) {
51+
func New(maxTTL time.Duration, ln int, pruneInterval time.Duration, refreshLastAccessOnGet bool) (m *TtlMap) {
5252
// if pruneInterval > maxTTL {
5353
// print("WARNING: TtlMap: pruneInterval > maxTTL\n")
5454
// }
5555
m = &TtlMap{m: make(map[CustomKeyType]*item, ln), stop: make(chan bool)}
5656
m.refresh = refreshLastAccessOnGet
57+
maxTTL /= 1000000000
58+
// print("maxTTL: ", maxTTL, "\n")
5759
go func() {
5860
for {
5961
select {
6062
case <-m.stop:
6163
return
62-
case now := <-time.Tick(time.Second * time.Duration(pruneInterval)):
64+
case now := <-time.Tick(pruneInterval):
6365
currentTime := now.Unix()
6466
m.l.Lock()
6567
for k, v := range m.m {
66-
//print("TICK:", currentTime, " ", v.lastAccess, " ", (currentTime - v.lastAccess), " ", maxTTL, " ", k, "\n")
68+
// print("TICK:", currentTime, " ", v.lastAccess, " ", currentTime-v.lastAccess, " ", maxTTL, " ", k, "\n")
6769
if currentTime-v.lastAccess >= int64(maxTTL) {
6870
delete(m.m, k)
6971
// print("deleting: ", k, "\n")
7072
}
7173
}
72-
// print("\n")
74+
// print("----\n")
7375
m.l.Unlock()
7476
}
7577
}
@@ -104,6 +106,15 @@ func (m *TtlMap) Get(k CustomKeyType) (v interface{}) {
104106
return
105107
}
106108

109+
func (m *TtlMap) GetNoUpdate(k CustomKeyType) (v interface{}) {
110+
m.l.Lock()
111+
if it, ok := m.m[k]; ok {
112+
v = it.Value
113+
}
114+
m.l.Unlock()
115+
return
116+
}
117+
107118
func (m *TtlMap) Delete(k CustomKeyType) bool {
108119
m.l.Lock()
109120
_, ok := m.m[k]

Diff for: ttlMap_test.go

+68-36
Original file line numberDiff line numberDiff line change
@@ -7,49 +7,50 @@ import (
77
)
88

99
func TestAllItemsExpired(t *testing.T) {
10-
maxTTL := 4 // time in seconds
11-
startSize := 3 // initial number of items in map
12-
pruneInterval := 1 // search for expired items every 'pruneInterval' seconds
13-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
10+
maxTTL := time.Duration(time.Second * 4) // time in seconds
11+
startSize := 3 // initial number of items in map
12+
pruneInterval := time.Duration(time.Second * 1) // search for expired items every 'pruneInterval' seconds
13+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
1414
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
15+
defer tm.Close()
1516

1617
// populate the TtlMap
1718
tm.Put("myString", "a b c")
1819
tm.Put("int_array", []int{1, 2, 3})
1920

20-
sleepTime := maxTTL + pruneInterval
21-
time.Sleep(time.Second * time.Duration(sleepTime))
21+
time.Sleep(maxTTL + pruneInterval)
2222
t.Logf("tm.len: %v\n", tm.Len())
2323
if tm.Len() > 0 {
2424
t.Errorf("t.Len should be 0, but actually equals %v\n", tm.Len())
2525
}
2626
}
2727

2828
func TestNoItemsExpired(t *testing.T) {
29-
maxTTL := 2 // time in seconds
30-
startSize := 3 // initial number of items in map
31-
pruneInterval := 3 // search for expired items every 'pruneInterval' seconds
32-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
29+
maxTTL := time.Duration(time.Second * 2) // time in seconds
30+
startSize := 3 // initial number of items in map
31+
pruneInterval := time.Duration(time.Second * 3) // search for expired items every 'pruneInterval' seconds
32+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
3333
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
34+
defer tm.Close()
3435

3536
// populate the TtlMap
3637
tm.Put("myString", "a b c")
3738
tm.Put("int_array", []int{1, 2, 3})
3839

39-
sleepTime := maxTTL
40-
time.Sleep(time.Second * time.Duration(sleepTime))
40+
time.Sleep(maxTTL)
4141
t.Logf("tm.len: %v\n", tm.Len())
4242
if tm.Len() != 2 {
4343
t.Fatalf("t.Len should equal 2, but actually equals %v\n", tm.Len())
4444
}
4545
}
4646

4747
func TestKeepFloat(t *testing.T) {
48-
maxTTL := 2 // time in seconds
49-
startSize := 3 // initial number of items in map
50-
pruneInterval := 1 // search for expired items every 'pruneInterval' seconds
51-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
48+
maxTTL := time.Duration(time.Second * 2) // time in seconds
49+
startSize := 3 // initial number of items in map
50+
pruneInterval := time.Duration(time.Second * 1) // search for expired items every 'pruneInterval' seconds
51+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
5252
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
53+
defer tm.Close()
5354

5455
// populate the TtlMap
5556
tm.Put("myString", "a b c")
@@ -63,8 +64,7 @@ func TestKeepFloat(t *testing.T) {
6364
}
6465
}()
6566

66-
sleepTime := maxTTL + pruneInterval
67-
time.Sleep(time.Second * time.Duration(sleepTime))
67+
time.Sleep(maxTTL + pruneInterval)
6868
if tm.Len() != 1 {
6969
t.Fatalf("t.Len should equal 1, but actually equals %v\n", tm.Len())
7070
}
@@ -77,11 +77,12 @@ func TestKeepFloat(t *testing.T) {
7777
}
7878

7979
func TestWithNoRefresh(t *testing.T) {
80-
maxTTL := 4 // time in seconds
81-
startSize := 3 // initial number of items in map
82-
pruneInterval := 1 // search for expired items every 'pruneInterval' seconds
83-
refreshLastAccessOnGet := false // do NOT update item's lastAccessTime on a .Get()
80+
maxTTL := time.Duration(time.Second * 4) // time in seconds
81+
startSize := 3 // initial number of items in map
82+
pruneInterval := time.Duration(time.Second * 1) // search for expired items every 'pruneInterval' seconds
83+
refreshLastAccessOnGet := false // do NOT update item's lastAccessTime on a .Get()
8484
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
85+
defer tm.Close()
8586

8687
// populate the TtlMap
8788
tm.Put("myString", "a b c")
@@ -94,20 +95,20 @@ func TestWithNoRefresh(t *testing.T) {
9495
}
9596
}()
9697

97-
sleepTime := maxTTL + pruneInterval
98-
time.Sleep(time.Second * time.Duration(sleepTime))
98+
time.Sleep(maxTTL + pruneInterval)
9999
t.Logf("tm.Len: %v\n", tm.Len())
100100
if tm.Len() != 0 {
101101
t.Errorf("t.Len should be 0, but actually equals %v\n", tm.Len())
102102
}
103103
}
104104

105105
func TestDelete(t *testing.T) {
106-
maxTTL := 2 // time in seconds
107-
startSize := 3 // initial number of items in map
108-
pruneInterval := 4 // search for expired items every 'pruneInterval' seconds
109-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
106+
maxTTL := time.Duration(time.Second * 2) // time in seconds
107+
startSize := 3 // initial number of items in map
108+
pruneInterval := time.Duration(time.Second * 4) // search for expired items every 'pruneInterval' seconds
109+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
110110
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
111+
defer tm.Close()
111112

112113
// populate the TtlMap
113114
tm.Put("myString", "a b c")
@@ -127,11 +128,12 @@ func TestDelete(t *testing.T) {
127128
}
128129

129130
func TestClear(t *testing.T) {
130-
maxTTL := 2 // time in seconds
131-
startSize := 3 // initial number of items in map
132-
pruneInterval := 4 // search for expired items every 'pruneInterval' seconds
133-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
131+
maxTTL := time.Duration(time.Second * 2) // time in seconds
132+
startSize := 3 // initial number of items in map
133+
pruneInterval := time.Duration(time.Second * 4) // search for expired items every 'pruneInterval' seconds
134+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
134135
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
136+
defer tm.Close()
135137

136138
// populate the TtlMap
137139
tm.Put("myString", "a b c")
@@ -149,11 +151,12 @@ func TestClear(t *testing.T) {
149151
}
150152

151153
func TestAllFunc(t *testing.T) {
152-
maxTTL := 2 // time in seconds
153-
startSize := 3 // initial number of items in map
154-
pruneInterval := 4 // search for expired items every 'pruneInterval' seconds
155-
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
154+
maxTTL := time.Duration(time.Second * 2) // time in seconds
155+
startSize := 3 // initial number of items in map
156+
pruneInterval := time.Duration(time.Second * 4) // search for expired items every 'pruneInterval' seconds
157+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
156158
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
159+
defer tm.Close()
157160

158161
// populate the TtlMap
159162
tm.Put("myString", "a b c")
@@ -177,3 +180,32 @@ func TestAllFunc(t *testing.T) {
177180
t.Fatalf("allItems and tm.m are not equal\n")
178181
}
179182
}
183+
184+
func TestGetNoUpdate(t *testing.T) {
185+
maxTTL := time.Duration(time.Second * 2) // time in seconds
186+
startSize := 3 // initial number of items in map
187+
pruneInterval := time.Duration(time.Second * 4) // search for expired items every 'pruneInterval' seconds
188+
refreshLastAccessOnGet := true // update item's lastAccessTime on a .Get()
189+
tm := New(maxTTL, startSize, pruneInterval, refreshLastAccessOnGet)
190+
defer tm.Close()
191+
192+
// populate the TtlMap
193+
tm.Put("myString", "a b c")
194+
tm.Put("int", 1234)
195+
tm.Put("floatPi", 3.1415)
196+
tm.Put("int_array", []int{1, 2, 3})
197+
tm.Put("boolean", true)
198+
199+
go func() {
200+
for range time.Tick(time.Second) {
201+
tm.GetNoUpdate("myString")
202+
tm.GetNoUpdate("int_array")
203+
}
204+
}()
205+
206+
time.Sleep(maxTTL + pruneInterval)
207+
t.Logf("tm.Len: %v\n", tm.Len())
208+
if tm.Len() != 0 {
209+
t.Errorf("t.Len should be 0, but actually equals %v\n", tm.Len())
210+
}
211+
}

0 commit comments

Comments
 (0)