001
014
015 package com.liferay.portal.kernel.cache.index;
016
017 import com.liferay.portal.kernel.cache.PortalCache;
018 import com.liferay.portal.kernel.cache.PortalCacheListener;
019 import com.liferay.portal.kernel.concurrent.ConcurrentHashSet;
020
021 import java.io.Serializable;
022
023 import java.util.Collections;
024 import java.util.HashSet;
025 import java.util.Set;
026 import java.util.concurrent.ConcurrentHashMap;
027 import java.util.concurrent.ConcurrentMap;
028
029
032 public class PortalCacheIndexer<I, K extends Serializable, V> {
033
034 public PortalCacheIndexer(
035 IndexEncoder<I, K> indexEncoder, PortalCache<K, V> portalCache) {
036
037 _indexEncoder = indexEncoder;
038
039 _portalCache = portalCache;
040
041 _portalCache.registerPortalCacheListener(
042 new IndexerPortalCacheListener());
043
044 for (K indexedCacheKey : _portalCache.getKeys()) {
045 _addIndexedCacheKey(indexedCacheKey);
046 }
047 }
048
049 public Set<K> getKeys(I index) {
050 Set<K> keys = _indexedCacheKeys.get(index);
051
052 if (keys == null) {
053 return Collections.emptySet();
054 }
055
056 return new HashSet<>(keys);
057 }
058
059 public void removeKeys(I index) {
060 Set<K> keys = _indexedCacheKeys.remove(index);
061
062 if (keys == null) {
063 return;
064 }
065
066 for (K key : keys) {
067 _portalCache.remove(key);
068 }
069 }
070
071 private void _addIndexedCacheKey(K key) {
072 I index = _indexEncoder.encode(key);
073
074 Set<K> keys = _indexedCacheKeys.get(index);
075
076 if (keys == null) {
077 Set<K> newKeys = new ConcurrentHashSet<>();
078
079 newKeys.add(key);
080
081 keys = _indexedCacheKeys.putIfAbsent(index, newKeys);
082
083 if (keys == null) {
084 return;
085 }
086 }
087
088 keys.add(key);
089 }
090
091 private void _removeIndexedCacheKey(K key) {
092 I index = _indexEncoder.encode(key);
093
094 Set<K> keys = _indexedCacheKeys.get(index);
095
096 if (keys == null) {
097 return;
098 }
099
100 keys.remove(key);
101
102 if (keys.isEmpty() && _indexedCacheKeys.remove(index, keys)) {
103 for (K victimIndexedCacheKey : keys) {
104 _addIndexedCacheKey(victimIndexedCacheKey);
105 }
106 }
107 }
108
109 private final ConcurrentMap<I, Set<K>> _indexedCacheKeys =
110 new ConcurrentHashMap<>();
111 private final IndexEncoder<I, K> _indexEncoder;
112 private final PortalCache<K, V> _portalCache;
113
114 private class IndexerPortalCacheListener
115 implements PortalCacheListener<K, V> {
116
117 @Override
118 public void dispose() {
119 _indexedCacheKeys.clear();
120 }
121
122 @Override
123 public void notifyEntryEvicted(
124 PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
125
126 _removeIndexedCacheKey(key);
127 }
128
129 @Override
130 public void notifyEntryExpired(
131 PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
132
133 _removeIndexedCacheKey(key);
134 }
135
136 @Override
137 public void notifyEntryPut(
138 PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
139
140 _addIndexedCacheKey(key);
141 }
142
143 @Override
144 public void notifyEntryRemoved(
145 PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
146
147 _removeIndexedCacheKey(key);
148 }
149
150 @Override
151 public void notifyEntryUpdated(
152 PortalCache<K, V> portalCache, K key, V value, int timeToLive) {
153 }
154
155 @Override
156 public void notifyRemoveAll(PortalCache<K, V> portalCache) {
157 _indexedCacheKeys.clear();
158 }
159
160 }
161
162 }