void clearCurrentCache() { lruCache.invalidateAll(); }
@Nullable @Override public Record loadRecord(@NotNull final String key, @NotNull final CacheHeaders cacheHeaders) { final Record record; try { record = lruCache.get(key, new Callable<Record>() { @Override public Record call() throws Exception { return nextCache().flatMap(new Function<NormalizedCache, Optional<Record>>() { @NotNull @Override public Optional<Record> apply(@NotNull NormalizedCache cache) { return Optional.fromNullable(cache.loadRecord(key, cacheHeaders)); } }).get(); // lruCache.get(key, callable) requires non-null. } }); } catch (Exception ignore) { return null; } if (cacheHeaders.hasHeader(ApolloCacheHeaders.EVICT_AFTER_READ)) { lruCache.invalidate(key); } return record; }
@NotNull protected Set<String> performMerge(@NotNull final Record apolloRecord, @NotNull final CacheHeaders cacheHeaders) { final Record oldRecord = lruCache.getIfPresent(apolloRecord.key()); if (oldRecord == null) { lruCache.put(apolloRecord.key(), apolloRecord); return apolloRecord.keys(); } else { Set<String> changedKeys = oldRecord.mergeWith(apolloRecord); //re-insert to trigger new weight calculation lruCache.put(apolloRecord.key(), oldRecord); return changedKeys; } }
LruNormalizedCache(EvictionPolicy evictionPolicy) { final CacheBuilder<Object, Object> lruCacheBuilder = CacheBuilder.newBuilder(); if (evictionPolicy.maxSizeBytes().isPresent()) { lruCacheBuilder.maximumWeight(evictionPolicy.maxSizeBytes().get()) .weigher(new Weigher<String, Record>() { @Override public int weigh(String key, Record value) { return key.getBytes(Charset.defaultCharset()).length + value.sizeEstimateBytes(); } }); } if (evictionPolicy.maxEntries().isPresent()) { lruCacheBuilder.maximumSize(evictionPolicy.maxEntries().get()); } if (evictionPolicy.expireAfterAccess().isPresent()) { lruCacheBuilder.expireAfterAccess(evictionPolicy.expireAfterAccess().get(), evictionPolicy.expireAfterAccessTimeUnit().get()); } if (evictionPolicy.expireAfterWrite().isPresent()) { lruCacheBuilder.expireAfterWrite(evictionPolicy.expireAfterWrite().get(), evictionPolicy.expireAfterWriteTimeUnit().get()); } lruCache = lruCacheBuilder.build(); }
@Override public boolean remove(@NotNull final CacheKey cacheKey, final boolean cascade) { checkNotNull(cacheKey, "cacheKey == null"); boolean result; result = nextCache().map(new Function<NormalizedCache, Boolean>() { @NotNull @Override public Boolean apply(@NotNull NormalizedCache cache) { return cache.remove(cacheKey, cascade); } }).or(Boolean.FALSE); Record record = lruCache.getIfPresent(cacheKey.key()); if (record != null) { lruCache.invalidate(cacheKey.key()); result = true; if (cascade) { for (CacheReference cacheReference : record.referencedFields()) { result = result & remove(CacheKey.from(cacheReference.key()), true); } } } return result; }
@NotNull public Set<String> removeOptimisticUpdates(@NotNull final UUID mutationId) { checkNotNull(mutationId, "mutationId == null"); Set<String> changedCacheKeys = new HashSet<>(); Set<String> removedKeys = new HashSet<>(); Map<String, RecordJournal> recordJournals = lruCache.asMap(); for (Map.Entry<String, RecordJournal> entry : recordJournals.entrySet()) { String cacheKey = entry.getKey(); RecordJournal journal = entry.getValue(); changedCacheKeys.addAll(journal.revert(mutationId)); if (journal.history.isEmpty()) { removedKeys.add(cacheKey); } } lruCache.invalidateAll(removedKeys); return changedCacheKeys; }
@Override public Map<Class, Map<String, Record>> dump() { Map<Class, Map<String, Record>> dump = new LinkedHashMap<>(); dump.put(this.getClass(), Collections.unmodifiableMap(new LinkedHashMap<>(lruCache.asMap()))); if (nextCache().isPresent()) { dump.putAll(nextCache().get().dump()); } return dump; } }
@Nullable @Override public Record loadRecord(@NotNull final String key, @NotNull final CacheHeaders cacheHeaders) { checkNotNull(key, "key == null"); checkNotNull(cacheHeaders, "cacheHeaders == null"); try { final Optional<Record> nonOptimisticRecord = nextCache() .flatMap(new Function<NormalizedCache, Optional<Record>>() { @NotNull @Override public Optional<Record> apply(@NotNull NormalizedCache cache) { return Optional.fromNullable(cache.loadRecord(key, cacheHeaders)); } }); final RecordJournal journal = lruCache.getIfPresent(key); if (journal != null) { return nonOptimisticRecord.map(new Function<Record, Record>() { @NotNull @Override public Record apply(@NotNull Record record) { Record result = record.clone(); result.mergeWith(journal.snapshot); return result; } }).or(journal.snapshot.clone()); } else { return nonOptimisticRecord.orNull(); } } catch (Exception ignore) { return null; } }
/** * @since 11.0 */ @Override public void invalidateAll(Iterable<?> keys) { delegate().invalidateAll(keys); }
/** * Clears all entries from the key and value reference queues. */ void clearReferenceQueues() { if (map.usesKeyReferences()) { clearKeyReferenceQueue(); } if (map.usesValueReferences()) { clearValueReferenceQueue(); } }
@Override @SuppressWarnings("unchecked") public boolean remove(Object o) { ReferenceEntry<K, V> e = (ReferenceEntry) o; ReferenceEntry<K, V> previous = e.getPreviousInWriteQueue(); ReferenceEntry<K, V> next = e.getNextInWriteQueue(); connectWriteOrder(previous, next); nullifyWriteOrder(e); return next != NullEntry.INSTANCE; }
@Override public void clear() { ReferenceEntry<K, V> e = head.getNextInAccessQueue(); while (e != head) { ReferenceEntry<K, V> next = e.getNextInAccessQueue(); nullifyAccessOrder(e); e = next; } head.setNextInAccessQueue(head); head.setPreviousInAccessQueue(head); }
@Override public ReferenceEntry<K, V> poll() { ReferenceEntry<K, V> next = head.getNextInAccessQueue(); if (next == head) { return null; } remove(next); return next; }
/** * @since 11.0 */ @Override public Map<K, V> getAllPresent(Iterable<?> keys) { return delegate().getAllPresent(keys); }
@NotNull public Set<String> mergeOptimisticUpdate(@NotNull final Record record) { checkNotNull(record, "record == null"); final RecordJournal journal = lruCache.getIfPresent(record.key()); if (journal == null) { lruCache.put(record.key(), new RecordJournal(record)); return Collections.singleton(record.key()); } else { return journal.commit(record); } }
@Override public boolean remove(@NotNull final CacheKey cacheKey, final boolean cascade) { checkNotNull(cacheKey, "cacheKey == null"); boolean result = nextCache().map(new Function<NormalizedCache, Boolean>() { @NotNull @Override public Boolean apply(@NotNull NormalizedCache cache) { return cache.remove(cacheKey, cascade); } }).or(Boolean.FALSE); RecordJournal recordJournal = lruCache.getIfPresent(cacheKey.key()); if (recordJournal != null) { lruCache.invalidate(cacheKey.key()); result = true; if (cascade) { for (CacheReference cacheReference : recordJournal.snapshot.referencedFields()) { result = result & remove(CacheKey.from(cacheReference.key()), true); } } } return result; }
@Override public Map<Class, Map<String, Record>> dump() { Map<String, Record> records = new LinkedHashMap<>(); for (Map.Entry<String, RecordJournal> entry : lruCache.asMap().entrySet()) { records.put(entry.getKey(), entry.getValue().snapshot); } Map<Class, Map<String, Record>> dump = new LinkedHashMap<>(); dump.put(this.getClass(), Collections.unmodifiableMap(records)); if (nextCache().isPresent()) { dump.putAll(nextCache().get().dump()); } return dump; }
@SuppressWarnings("ResultOfMethodCallIgnored") @Override public void clearAll() { lruCache.invalidateAll(); //noinspection ResultOfMethodCallIgnored nextCache().apply(new Action<NormalizedCache>() { @Override public void apply(@NotNull NormalizedCache cache) { cache.clearAll(); } }); }