Project

General

Profile

« Previous | Next » 

Revision 922b1ce9

Added by Andreas Kohlbecker almost 4 years ago

ref #9152 implementing service level cache for cdm preferences with locking mechanism

View differences:

cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/service/PreferenceServiceImpl.java
9 9

  
10 10
package eu.etaxonomy.cdm.api.service;
11 11

  
12
import java.util.ArrayList;
13
import java.util.Collection;
12 14
import java.util.List;
15
import java.util.Map;
16
import java.util.concurrent.ConcurrentHashMap;
13 17

  
14 18
import org.apache.log4j.Logger;
15 19
import org.springframework.beans.factory.annotation.Autowired;
......
39 43
    @Autowired
40 44
    private IPreferenceDao dao;
41 45

  
42
	@Override
46
    private Map<String, CdmPreference> cache = new ConcurrentHashMap<>();
47

  
48
    private boolean cacheIsComplete = false;
49

  
50
    private boolean cacheIsLocked = false;
51

  
52
    @Override
43 53
	public CdmPreference findExact(PrefKey key) {
44
		return dao.get(key);
54
		String cacheKey = cacheKey(key);
55
        return fromCacheGet(key, cacheKey);
45 56
	}
46 57

  
47 58
    @Override
48 59
    public CdmPreference find(PrefKey key) {
49
        List<CdmPreference> prefs = dao.list();
50
        CdmPreference pref = PreferenceResolver.resolve(prefs, key);
60
        CdmPreference pref = PreferenceResolver.resolve(list(), key);
51 61
        return pref;
52 62
    }
53 63

  
......
73 83
    @Transactional(readOnly = false)
74 84
	public void set(CdmPreference preference) {
75 85
		dao.set(preference);
86
		cachePut(preference);
76 87
	}
77 88

  
78
	@Override
89
    @Override
79 90
    @Transactional(readOnly = false)
80
    public void remove(PrefKey preference) {
81
        dao.remove(preference);
91
    public void remove(PrefKey key) {
92
        dao.remove(key);
93
        removeFromCache(key);
82 94
    }
83 95

  
84
	@Override
96
    @Override
85 97
	public long count() {
86 98
		return dao.count();
87 99
	}
88 100

  
89 101
	@Override
90 102
    public List<CdmPreference> list() {
91
        return dao.list();
103
	    if(!cacheIsComplete) {
104
	        cacheFullUpdate();
105
	    }
106
        return new ArrayList<CdmPreference>(cacheValues());
92 107
    }
93 108

  
94 109
    @Override
95 110
    public List<CdmPreference> list(IPreferencePredicate<?> predicate) {
111
        // using the cache for this method makes not much sense
96 112
        return dao.list(predicate);
97 113
    }
98 114

  
99 115
    @Override
100
    public Object find(TaxonNode taxonNode, String predicate) {
101
        return dao.find(taxonNode, predicate);
116
    public CdmPreference find(TaxonNode taxonNode, String predicate) {
117
        String cacheKey = cacheKey(taxonNode, predicate);
118
        return fromCacheOrFind(taxonNode, predicate, cacheKey);
102 119
    }
103 120

  
104 121
    @Override
105 122
    public CdmPreference find(TaxonNode taxonNode, IPreferencePredicate<?> predicate){
106
        return dao.find(taxonNode, predicate.getKey());
123
        return find(taxonNode, predicate.getKey());
107 124
    }
108 125

  
109 126
// ********************** NOT YET HANDLED *******************/
......
130 147
            throw new RuntimeException("mapToTaxonNode not yet implemented for " + taxonNodeRelatedCdmBase.getClass().getSimpleName());
131 148
        }
132 149
    }
150

  
151
    // ====================== Cache methods ======================= //
152
    /**
153
     * Concatenates subject and predicate as key for the cache map
154
     */
155
    private String cacheKey(PrefKey key) {
156
        return key.getSubject() + key.getPredicate();
157
    }
158

  
159
    private String cacheKey(TaxonNode taxonNode, String predicate) {
160
        return taxonNode.treeIndex() + predicate;
161
    }
162

  
163

  
164
    // --------------- non locking cache read methods --------------- //
165

  
166
    protected Collection<CdmPreference> cacheValues() {
167
        waitForCache();
168
        return cache.values();
169
    }
170

  
171
    protected CdmPreference fromCacheGet(PrefKey key, String cacheKey) {
172
        waitForCache();
173
        return cache.computeIfAbsent(cacheKey, k -> dao.get(key));
174
    }
175

  
176

  
177
    protected CdmPreference fromCacheOrFind(TaxonNode taxonNode, String predicate, String cacheKey) {
178
        waitForCache();
179
        return cache.computeIfAbsent(cacheKey, k -> dao.find(taxonNode, predicate));
180
    }
181

  
182
    // --------------- cache locking methods --------------- //
183

  
184
    protected void cachePut(CdmPreference preference) {
185
        waitForCache();
186
        cacheIsLocked = true;
187
        cache.put(cacheKey(preference.getKey()), preference);
188
        cacheIsLocked = false;
189
    }
190

  
191

  
192
    protected void removeFromCache(PrefKey key) {
193
        waitForCache();
194
        cacheIsLocked = true;
195
        cache.remove(cacheKey(key));
196
        cacheIsLocked = false;
197
    }
198

  
199
    protected void cacheFullUpdate() {
200
        waitForCache();
201
        cacheIsLocked = true;
202
        cache.clear();
203
        for(CdmPreference pref :  dao.list()){
204
            cache.put(cacheKey(pref.getKey()), pref);
205
        }
206
        cacheIsLocked = false;
207
    }
208

  
209
    protected void waitForCache() {
210
        while(cacheIsLocked) {
211
            try {
212
                Thread.sleep(1);
213
            } catch (InterruptedException e) {
214
                // just keep on sleeping, we may improve this later on
215
            }
216
        }
217
    }
218

  
133 219
}

Also available in: Unified diff