001
014
015 package com.liferay.portal.kernel.cache.index;
016
017 import com.liferay.portal.kernel.cache.CacheListener;
018 import com.liferay.portal.kernel.cache.PortalCache;
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.registerCacheListener(new IndexerCacheListener());
042
043 for (K indexedCacheKey : _portalCache.getKeys()) {
044 _addIndexedCacheKey(indexedCacheKey);
045 }
046 }
047
048 public Set<K> getKeys(I index) {
049 Set<K> keys = _indexedCacheKeys.get(index);
050
051 if (keys == null) {
052 return Collections.emptySet();
053 }
054
055 return new HashSet<K>(keys);
056 }
057
058 public void removeKeys(I index) {
059 Set<K> keys = _indexedCacheKeys.remove(index);
060
061 if (keys == null) {
062 return;
063 }
064
065 for (K key : keys) {
066 _portalCache.remove(key);
067 }
068 }
069
070 private void _addIndexedCacheKey(K key) {
071 I index = _indexEncoder.encode(key);
072
073 Set<K> keys = _indexedCacheKeys.get(index);
074
075 if (keys == null) {
076 Set<K> newKeys = new ConcurrentHashSet<K>();
077
078 newKeys.add(key);
079
080 keys = _indexedCacheKeys.putIfAbsent(index, newKeys);
081
082 if (keys == null) {
083 return;
084 }
085 }
086
087 keys.add(key);
088 }
089
090 private void _removeIndexedCacheKey(K key) {
091 I index = _indexEncoder.encode(key);
092
093 Set<K> keys = _indexedCacheKeys.get(index);
094
095 if (keys == null) {
096 return;
097 }
098
099 keys.remove(key);
100
101 if (keys.isEmpty() && _indexedCacheKeys.remove(index, keys)) {
102 for (K victimIndexedCacheKey : keys) {
103 _addIndexedCacheKey(victimIndexedCacheKey);
104 }
105 }
106 }
107
108 private final ConcurrentMap<I, Set<K>> _indexedCacheKeys =
109 new ConcurrentHashMap<I, Set<K>>();
110 private final IndexEncoder<I, K> _indexEncoder;
111 private final PortalCache<K, V> _portalCache;
112
113 private class IndexerCacheListener implements CacheListener<K, V> {
114
115 @Override
116 public void notifyEntryEvicted(
117 PortalCache<K, V> portalCache, K key, V value) {
118
119 _removeIndexedCacheKey(key);
120 }
121
122 @Override
123 public void notifyEntryExpired(
124 PortalCache<K, V> portalCache, K key, V value) {
125
126 _removeIndexedCacheKey(key);
127 }
128
129 @Override
130 public void notifyEntryPut(
131 PortalCache<K, V> portalCache, K key, V value) {
132
133 _addIndexedCacheKey(key);
134 }
135
136 @Override
137 public void notifyEntryRemoved(
138 PortalCache<K, V> portalCache, K key, V value) {
139
140 _removeIndexedCacheKey(key);
141 }
142
143 @Override
144 public void notifyEntryUpdated(
145 PortalCache<K, V> portalCache, K key, V value) {
146 }
147
148 @Override
149 public void notifyRemoveAll(PortalCache<K, V> portalCache) {
150 _indexedCacheKeys.clear();
151 }
152
153 }
154
155 }