-
Notifications
You must be signed in to change notification settings - Fork 75
/
viewmodellistcache.go
141 lines (124 loc) · 3.64 KB
/
viewmodellistcache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2015 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Code for ViewModelListCache created
// from https://github.com/streamrail/concurrent-map/blob/master/concurrent_map_template.txt
package orchestrator
import (
"github.com/andreaskoch/allmark/web/view/viewmodel"
"hash/fnv"
"sync"
)
var VIEWMODELLISTCACHE_SHARD_COUNT = 32
// A "thread" safe map of type string:[]viewmodel.Model.
// To avoid lock bottlenecks this map is dived to several (VIEWMODELLISTCACHE_SHARD_COUNT) map shards.
type ViewModelListCache []*ConcurrentViewModelListMapShared
type ConcurrentViewModelListMapShared struct {
items map[string][]viewmodel.Model
sync.RWMutex // Read Write mutex, guards access to internal map.
}
// Creates a new concurrent viewmodel cache map.
func newViewModelListCache() ViewModelListCache {
m := make(ViewModelListCache, VIEWMODELLISTCACHE_SHARD_COUNT)
for i := 0; i < VIEWMODELLISTCACHE_SHARD_COUNT; i++ {
m[i] = &ConcurrentViewModelListMapShared{items: make(map[string][]viewmodel.Model)}
}
return m
}
// Returns shard under given key
func (m ViewModelListCache) GetShard(key string) *ConcurrentViewModelListMapShared {
hasher := fnv.New32()
hasher.Write([]byte(key))
return m[int(hasher.Sum32())%VIEWMODELLISTCACHE_SHARD_COUNT]
}
// Sets the given value under the specified key.
func (m *ViewModelListCache) Set(key string, value []viewmodel.Model) {
// Get map shard.
shard := m.GetShard(key)
shard.Lock()
defer shard.Unlock()
shard.items[key] = value
}
// Retrieves an element from map under given key.
func (m ViewModelListCache) Get(key string) ([]viewmodel.Model, bool) {
// Get shard
shard := m.GetShard(key)
shard.RLock()
defer shard.RUnlock()
// Get item from shard.
val, ok := shard.items[key]
return val, ok
}
// Returns the number of elements within the map.
func (m ViewModelListCache) Count() int {
count := 0
for i := 0; i < VIEWMODELLISTCACHE_SHARD_COUNT; i++ {
shard := m[i]
shard.RLock()
count += len(shard.items)
shard.RUnlock()
}
return count
}
// Looks up an item under specified key
func (m *ViewModelListCache) Has(key string) bool {
// Get shard
shard := m.GetShard(key)
shard.RLock()
defer shard.RUnlock()
// See if element is within shard.
_, ok := shard.items[key]
return ok
}
// Removes an element from the map.
func (m *ViewModelListCache) Remove(key string) {
// Try to get shard.
shard := m.GetShard(key)
shard.Lock()
defer shard.Unlock()
delete(shard.items, key)
}
// Checks if map is empty.
func (m *ViewModelListCache) IsEmpty() bool {
return m.Count() == 0
}
// Used by the Iter & IterBuffered functions to wrap two variables together over a channel,
type ViewModelListCacheTuple struct {
Key string
Val []viewmodel.Model
}
// Returns an iterator which could be used in a for range loop.
func (m ViewModelListCache) Iter() <-chan ViewModelListCacheTuple {
ch := make(chan ViewModelListCacheTuple)
go func() {
// Foreach shard.
for _, shard := range m {
// Foreach key, value pair.
shard.RLock()
for key, val := range shard.items {
ch <- ViewModelListCacheTuple{key, val}
}
shard.RUnlock()
}
close(ch)
}()
return ch
}
// Returns a buffered iterator which could be used in a for range loop.
func (m ViewModelListCache) IterBuffered() <-chan ViewModelListCacheTuple {
ch := make(chan ViewModelListCacheTuple, m.Count())
go func() {
// Foreach shard.
for _, shard := range m {
// Foreach key, value pair.
shard.RLock()
for key, val := range shard.items {
ch <- ViewModelListCacheTuple{key, val}
}
shard.RUnlock()
}
close(ch)
}()
return ch
}