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

ben-manes / caffeine / #3896

pending completion
#3896

push

github-actions

ben-manes
upgrade jamm library (memory meter)

7542 of 7616 relevant lines covered (99.03%)

0.99 hits per line

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

93.51
/jcache/src/main/java/com/github/benmanes/caffeine/jcache/LoadingCacheProxy.java
1
/*
2
 * Copyright 2015 Ben Manes. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.github.benmanes.caffeine.jcache;
17

18
import static java.util.stream.Collectors.toUnmodifiableList;
19

20
import java.util.List;
21
import java.util.Map;
22
import java.util.Objects;
23
import java.util.Optional;
24
import java.util.Set;
25
import java.util.concurrent.CompletableFuture;
26
import java.util.concurrent.Executor;
27

28
import javax.cache.Cache;
29
import javax.cache.CacheException;
30
import javax.cache.CacheManager;
31
import javax.cache.expiry.ExpiryPolicy;
32
import javax.cache.integration.CacheLoader;
33
import javax.cache.integration.CompletionListener;
34

35
import org.checkerframework.checker.nullness.qual.Nullable;
36

37
import com.github.benmanes.caffeine.cache.LoadingCache;
38
import com.github.benmanes.caffeine.cache.Ticker;
39
import com.github.benmanes.caffeine.jcache.configuration.CaffeineConfiguration;
40
import com.github.benmanes.caffeine.jcache.event.EventDispatcher;
41
import com.github.benmanes.caffeine.jcache.management.JCacheStatisticsMXBean;
42

43
/**
44
 * An implementation of JSR-107 {@link Cache} backed by a Caffeine loading cache.
45
 *
46
 * @author ben.manes@gmail.com (Ben Manes)
47
 */
48
@SuppressWarnings("OvershadowingSubclassFields")
49
public final class LoadingCacheProxy<K, V> extends CacheProxy<K, V> {
50
  private final LoadingCache<K, Expirable<V>> cache;
51

52
  @SuppressWarnings("PMD.ExcessiveParameterList")
53
  public LoadingCacheProxy(String name, Executor executor, CacheManager cacheManager,
54
      CaffeineConfiguration<K, V> configuration, LoadingCache<K, Expirable<V>> cache,
55
      EventDispatcher<K, V> dispatcher, CacheLoader<K, V> cacheLoader,
56
      ExpiryPolicy expiry, Ticker ticker, JCacheStatisticsMXBean statistics) {
57
    super(name, executor, cacheManager, configuration, cache, dispatcher,
1✔
58
        Optional.of(cacheLoader), expiry, ticker, statistics);
1✔
59
    this.cache = cache;
1✔
60
  }
1✔
61

62
  @Override
63
  @SuppressWarnings("PMD.AvoidCatchingNPE")
64
  public @Nullable V get(K key) {
65
    requireNotClosed();
1✔
66
    try {
67
      return getOrLoad(key);
1✔
68
    } catch (NullPointerException | IllegalStateException | ClassCastException | CacheException e) {
1✔
69
      throw e;
1✔
70
    } catch (RuntimeException e) {
×
71
      throw new CacheException(e);
×
72
    } finally {
73
      dispatcher.awaitSynchronous();
1✔
74
    }
75
  }
76

77
  /** Retrieves the value from the cache, loading it if necessary. */
78
  @SuppressWarnings("PMD.AvoidDeeplyNestedIfStmts")
79
  private @Nullable V getOrLoad(K key) {
80
    boolean statsEnabled = statistics.isEnabled();
1✔
81
    long start = statsEnabled ? ticker.read() : 0L;
1✔
82

83
    long millis = 0L;
1✔
84
    Expirable<V> expirable = cache.getIfPresent(key);
1✔
85
    if ((expirable != null) && !expirable.isEternal()) {
1✔
86
      millis = nanosToMillis((start == 0L) ? ticker.read() : start);
1✔
87
      if (expirable.hasExpired(millis)) {
1✔
88
        var expired = expirable;
1✔
89
        cache.asMap().computeIfPresent(key, (k, e) -> {
1✔
90
          if (e == expired) {
1✔
91
            dispatcher.publishExpired(this, key, expired.get());
1✔
92
            statistics.recordEvictions(1);
1✔
93
            return null;
1✔
94
          }
95
          return e;
×
96
        });
97
        expirable = null;
1✔
98
      }
99
    }
100

101
    if (expirable == null) {
1✔
102
      expirable = cache.get(key);
1✔
103
      statistics.recordMisses(1L);
1✔
104
    } else {
105
      statistics.recordHits(1L);
1✔
106
    }
107

108
    V value = null;
1✔
109
    if (expirable != null) {
1✔
110
      setAccessExpireTime(key, expirable, millis);
1✔
111
      value = copyValue(expirable);
1✔
112
    }
113
    if (statsEnabled) {
1✔
114
      statistics.recordGetTime(ticker.read() - start);
1✔
115
    }
116
    return value;
1✔
117
  }
118

119
  @Override
120
  public Map<K, V> getAll(Set<? extends K> keys) {
121
    return getAll(keys, true);
1✔
122
  }
123

124
  /** Returns the entries, loading if necessary, and optionally updates their access expiry time. */
125
  @SuppressWarnings("PMD.AvoidCatchingNPE")
126
  private Map<K, V> getAll(Set<? extends K> keys, boolean updateAccessTime) {
127
    requireNotClosed();
1✔
128
    boolean statsEnabled = statistics.isEnabled();
1✔
129
    long start = statsEnabled ? ticker.read() : 0L;
1✔
130
    try {
131
      Map<K, Expirable<V>> entries = getAndFilterExpiredEntries(keys, updateAccessTime);
1✔
132

133
      if (entries.size() != keys.size()) {
1✔
134
        List<K> keysToLoad = keys.stream()
1✔
135
            .filter(key -> !entries.containsKey(key))
1✔
136
            .collect(toUnmodifiableList());
1✔
137
        entries.putAll(cache.getAll(keysToLoad));
1✔
138
      }
139

140
      Map<K, V> result = copyMap(entries);
1✔
141
      if (statsEnabled) {
1✔
142
        statistics.recordGetTime(ticker.read() - start);
1✔
143
      }
144
      return result;
1✔
145
    } catch (NullPointerException | IllegalStateException | ClassCastException | CacheException e) {
1✔
146
      throw e;
1✔
147
    } catch (RuntimeException e) {
×
148
      throw new CacheException(e);
×
149
    } finally {
150
      dispatcher.awaitSynchronous();
1✔
151
    }
152
  }
153

154
  @Override
155
  @SuppressWarnings({"CheckReturnValue", "FutureReturnValueIgnored"})
156
  public void loadAll(Set<? extends K> keys, boolean replaceExistingValues,
157
      CompletionListener completionListener) {
158
    requireNotClosed();
1✔
159
    keys.forEach(Objects::requireNonNull);
1✔
160
    CompletionListener listener = (completionListener == null)
1✔
161
        ? NullCompletionListener.INSTANCE
1✔
162
        : completionListener;
1✔
163

164
    var future = CompletableFuture.runAsync(() -> {
1✔
165
      try {
166
        if (replaceExistingValues) {
1✔
167
          @SuppressWarnings("NullAway")
168
          Map<K, V> loaded = cacheLoader.orElseThrow().loadAll(keys);
1✔
169
          for (var entry : loaded.entrySet()) {
1✔
170
            putNoCopyOrAwait(entry.getKey(), entry.getValue(), /* publishToWriter */ false);
1✔
171
          }
1✔
172
        } else {
1✔
173
          getAll(keys, /* updateAccessTime */ false);
1✔
174
        }
175
        listener.onCompletion();
1✔
176
      } catch (RuntimeException e) {
1✔
177
        listener.onException(e);
1✔
178
      } finally {
179
        dispatcher.ignoreSynchronous();
1✔
180
      }
181
    }, executor);
1✔
182

183
    inFlight.add(future);
1✔
184
    future.whenComplete((r, e) -> inFlight.remove(future));
1✔
185
  }
1✔
186
}
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