• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

alibaba / jetcache / #405

16 Apr 2024 05:58AM UTC coverage: 0.0% (-88.9%) from 88.866%
#405

push

areyouok
add encoding to fix coverage report

0 of 5353 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/jetcache-core/src/main/java/com/alicp/jetcache/MultiLevelCache.java
1
package com.alicp.jetcache;
2

3
import java.util.Arrays;
4
import java.util.HashMap;
5
import java.util.HashSet;
6
import java.util.Map;
7
import java.util.Objects;
8
import java.util.Set;
9
import java.util.concurrent.CompletableFuture;
10
import java.util.concurrent.TimeUnit;
11

12
/**
13
 * Created on 16/9/13.
14
 *
15
 * @author huangli
16
 */
17
public class MultiLevelCache<K, V> extends AbstractCache<K, V> {
18

19
    private Cache[] caches;
20

21
    private MultiLevelCacheConfig<K, V> config;
22

23
    @SuppressWarnings("unchecked")
24
    @Deprecated
25
    public MultiLevelCache(Cache... caches) throws CacheConfigException {
×
26
        this.caches = caches;
×
27
        checkCaches();
×
28
        CacheConfig lastConfig = caches[caches.length - 1].config();
×
29
        config = new MultiLevelCacheConfig<>();
×
30
        config.setCaches(Arrays.asList(caches));
×
31
        config.setExpireAfterWriteInMillis(lastConfig.getExpireAfterWriteInMillis());
×
32
        config.setCacheNullValue(lastConfig.isCacheNullValue());
×
33
    }
×
34

35
    @SuppressWarnings("unchecked")
36
    public MultiLevelCache(MultiLevelCacheConfig<K, V> cacheConfig) throws CacheConfigException {
×
37
        this.config = cacheConfig;
×
38
        this.caches = cacheConfig.getCaches().toArray(new Cache[]{});
×
39
        checkCaches();
×
40
    }
×
41

42
    private void checkCaches() {
43
        if (caches == null || caches.length == 0) {
×
44
            throw new IllegalArgumentException();
×
45
        }
46
        for (Cache c : caches) {
×
47
            if (c.config().getLoader() != null) {
×
48
                throw new CacheConfigException("Loader on sub cache is not allowed, set the loader into MultiLevelCache.");
×
49
            }
50
        }
51
    }
×
52

53
    public Cache[] caches() {
54
        return caches;
×
55
    }
56

57
    @Override
58
    public MultiLevelCacheConfig<K, V> config() {
59
        return config;
×
60
    }
61

62
    @Override
63
    public CacheResult PUT(K key, V value) {
64
        if (config.isUseExpireOfSubCache()) {
×
65
            return PUT(key, value, 0, null);
×
66
        } else {
67
            return PUT(key, value, config().getExpireAfterWriteInMillis(), TimeUnit.MILLISECONDS);
×
68
        }
69
    }
70

71
    @Override
72
    public CacheResult PUT_ALL(Map<? extends K, ? extends V> map) {
73
        if (config.isUseExpireOfSubCache()) {
×
74
            return PUT_ALL(map, 0, null);
×
75
        } else {
76
            return PUT_ALL(map, config().getExpireAfterWriteInMillis(), TimeUnit.MILLISECONDS);
×
77
        }
78
    }
79

80
    @Override
81
    protected CacheGetResult<V> do_GET(K key) {
82
        for (int i = 0; i < caches.length; i++) {
×
83
            Cache cache = caches[i];
×
84
            CacheGetResult result = cache.GET(key);
×
85
            if (result.isSuccess()) {
×
86
                CacheValueHolder<V> holder = unwrapHolder(result.getHolder());
×
87
                checkResultAndFillUpperCache(key, i, holder);
×
88
                return new CacheGetResult(CacheResultCode.SUCCESS, null, holder);
×
89
            }
90
        }
91
        return CacheGetResult.NOT_EXISTS_WITHOUT_MSG;
×
92
    }
93

94
    private CacheValueHolder<V> unwrapHolder(CacheValueHolder<V> h) {
95
        // if @Cached or @CacheCache change type from REMOTE to BOTH (or from BOTH to REMOTE),
96
        // during the dev/publish process, the value type which different application server put into cache server will be different
97
        // (CacheValueHolder<V> and CacheValueHolder<CacheValueHolder<V>>, respectively).
98
        // So we need correct the problem at here and in CacheGetResult.
99
        Objects.requireNonNull(h);
×
100
        if (h.getValue() instanceof CacheValueHolder) {
×
101
            return (CacheValueHolder<V>) h.getValue();
×
102
        } else {
103
            return h;
×
104
        }
105
    }
106

107
    private void checkResultAndFillUpperCache(K key, int i, CacheValueHolder<V> h) {
108
        Objects.requireNonNull(h);
×
109
        long currentExpire = h.getExpireTime();
×
110
        long now = System.currentTimeMillis();
×
111
        if (now <= currentExpire) {
×
112
            if(config.isUseExpireOfSubCache()){
×
113
                PUT_caches(i, key, h.getValue(), 0, null);
×
114
            } else {
115
                long restTtl = currentExpire - now;
×
116
                if (restTtl > 0) {
×
117
                    PUT_caches(i, key, h.getValue(), restTtl, TimeUnit.MILLISECONDS);
×
118
                }
119
            }
120
        }
121
    }
×
122

123
    @Override
124
    protected MultiGetResult<K, V> do_GET_ALL(Set<? extends K> keys) {
125
        HashMap<K, CacheGetResult<V>> resultMap = new HashMap<>();
×
126
        Set<K> restKeys = new HashSet<>(keys);
×
127
        for (int i = 0; i < caches.length; i++) {
×
128
            if (restKeys.size() == 0) {
×
129
                break;
×
130
            }
131
            Cache<K, CacheValueHolder<V>> c = caches[i];
×
132
            MultiGetResult<K, CacheValueHolder<V>> allResult = c.GET_ALL(restKeys);
×
133
            if (allResult.isSuccess() && allResult.getValues() != null) {
×
134
                for (Map.Entry<K, CacheGetResult<CacheValueHolder<V>>> en : allResult.getValues().entrySet()) {
×
135
                    K key = en.getKey();
×
136
                    CacheGetResult result = en.getValue();
×
137
                    if (result.isSuccess()) {
×
138
                        CacheValueHolder<V> holder = unwrapHolder(result.getHolder());
×
139
                        checkResultAndFillUpperCache(key, i, holder);
×
140
                        resultMap.put(key, new CacheGetResult(CacheResultCode.SUCCESS, null, holder));
×
141
                        restKeys.remove(key);
×
142
                    }
143
                }
×
144
            }
145
        }
146
        for (K k : restKeys) {
×
147
            resultMap.put(k, CacheGetResult.NOT_EXISTS_WITHOUT_MSG);
×
148
        }
×
149
        return new MultiGetResult<>(CacheResultCode.SUCCESS, null, resultMap);
×
150
    }
151

152
    @Override
153
    protected CacheResult do_PUT(K key, V value, long expireAfterWrite, TimeUnit timeUnit) {
154
        return PUT_caches(caches.length, key, value, expireAfterWrite, timeUnit);
×
155
    }
156

157
    @Override
158
    protected CacheResult do_PUT_ALL(Map<? extends K, ? extends V> map, long expireAfterWrite, TimeUnit timeUnit) {
159
        CompletableFuture<ResultData> future = CompletableFuture.completedFuture(null);
×
160
        for (Cache c : caches) {
×
161
            CacheResult r;
162
            if(timeUnit == null) {
×
163
                r = c.PUT_ALL(map);
×
164
            } else {
165
                r = c.PUT_ALL(map, expireAfterWrite, timeUnit);
×
166
            }
167
            future = combine(future, r);
×
168
        }
169
        return new CacheResult(future);
×
170
    }
171

172
    private CacheResult PUT_caches(int lastIndex, K key, V value, long expire, TimeUnit timeUnit) {
173
        CompletableFuture<ResultData> future = CompletableFuture.completedFuture(null);
×
174
        for (int i = 0; i < lastIndex; i++) {
×
175
            Cache cache = caches[i];
×
176
            CacheResult r;
177
            if (timeUnit == null) {
×
178
                r = cache.PUT(key, value);
×
179
            } else {
180
                r = cache.PUT(key, value, expire, timeUnit);
×
181
            }
182
            future = combine(future, r);
×
183
        }
184
        return new CacheResult(future);
×
185
    }
186

187
    private CompletableFuture<ResultData> combine(CompletableFuture<ResultData> future, CacheResult result) {
188
        return future.thenCombine(result.future(), (d1, d2) -> {
×
189
            if (d1 == null) {
×
190
                return d2;
×
191
            }
192
            if (d1.getResultCode() != d2.getResultCode()) {
×
193
                return new ResultData(CacheResultCode.PART_SUCCESS, null, null);
×
194
            }
195
            return d1;
×
196
        });
197
    }
198

199
    @Override
200
    protected CacheResult do_REMOVE(K key) {
201
        CompletableFuture<ResultData> future = CompletableFuture.completedFuture(null);
×
202
        for (Cache cache : caches) {
×
203
            CacheResult r = cache.REMOVE(key);
×
204
            future = combine(future, r);
×
205
        }
206
        return new CacheResult(future);
×
207
    }
208

209
    @Override
210
    protected CacheResult do_REMOVE_ALL(Set<? extends K> keys) {
211
        CompletableFuture<ResultData> future = CompletableFuture.completedFuture(null);
×
212
        for (Cache cache : caches) {
×
213
            CacheResult r = cache.REMOVE_ALL(keys);
×
214
            future = combine(future, r);
×
215
        }
216
        return new CacheResult(future);
×
217
    }
218

219
    @Override
220
    public <T> T unwrap(Class<T> clazz) {
221
        Objects.requireNonNull(clazz);
×
222
        for (Cache cache : caches) {
×
223
            try {
224
                T obj = (T) cache.unwrap(clazz);
×
225
                if (obj != null) {
×
226
                    return obj;
×
227
                }
228
            } catch (IllegalArgumentException e) {
×
229
                // ignore
230
            }
×
231
        }
232
        throw new IllegalArgumentException(clazz.getName());
×
233
    }
234

235
    @Override
236
    public AutoReleaseLock tryLock(K key, long expire, TimeUnit timeUnit) {
237
        if (key == null) {
×
238
            return null;
×
239
        }
240
        return caches[caches.length - 1].tryLock(key, expire, timeUnit);
×
241
    }
242

243
    @Override
244
    public boolean putIfAbsent(K key, V value) {
245
        throw new UnsupportedOperationException("putIfAbsent is not supported by MultiLevelCache");
×
246
    }
247

248
    @Override
249
    protected CacheResult do_PUT_IF_ABSENT(K key, V value, long expireAfterWrite, TimeUnit timeUnit) {
250
        throw new UnsupportedOperationException("PUT_IF_ABSENT is not supported by MultiLevelCache");
×
251
    }
252

253
    @Override
254
    public void close() {
255
        super.close();
×
256
        for (Cache c : caches) {
×
257
            c.close();
×
258
        }
259
    }
×
260
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc