1 7 package org.mmbase.cache; 8 9 import java.util.*; 10 11 import org.mmbase.core.event.Event; 12 import org.mmbase.core.event.NodeEvent; 13 import org.mmbase.core.event.NodeEventListener; 14 import org.mmbase.core.event.RelationEvent; 15 import org.mmbase.core.event.RelationEventListener; 16 import org.mmbase.module.core.*; 17 import org.mmbase.util.logging.*; 18 19 import org.mmbase.storage.search.*; 20 21 import org.mmbase.storage.search.implementation.database.BasicSqlHandler; 22 import org.mmbase.bridge.implementation.BasicQuery; 23 24 40 41 abstract public class QueryResultCache extends Cache { 42 43 private static final Logger log = Logging.getLoggerInstance(QueryResultCache.class); 44 45 49 private static final Map queryCaches = new HashMap(); 50 51 57 58 61 final BasicSqlHandler sqlHandler = new BasicSqlHandler(); 62 63 private final ChainedReleaseStrategy releaseStrategy; 64 65 72 73 74 private final Map observers = new HashMap(); 79 80 QueryResultCache(int size) { 81 super(size); 82 releaseStrategy = new ChainedReleaseStrategy(); 83 log.debug("Instantiated a " + this.getClass().getName() + " (" + releaseStrategy + ")"); if (queryCaches.put(this.getName(), this) != null) { 85 log.error("" + queryCaches + "already containing " + this + "!!"); 86 } 87 } 88 89 92 public void addReleaseStrategies(List strategies) { 93 if (strategies != null) { 94 for (Iterator iter = strategies.iterator(); iter.hasNext();) { 95 ReleaseStrategy element = (ReleaseStrategy) iter.next(); 96 log.debug(("adding strategy " + element.getName() + " to cache " + getName())); 97 addReleaseStrategy(element); 98 } 99 } 100 } 101 102 108 public void addReleaseStrategy(ReleaseStrategy releaseStrategy) { 109 this.releaseStrategy.addReleaseStrategy(releaseStrategy); 110 } 111 112 115 public ChainedReleaseStrategy getReleaseStrategy() { 116 return releaseStrategy; 117 } 118 119 122 public Iterator observerIterator(){ 123 List observerList = new ArrayList(); 124 synchronized(this){ 125 observerList.addAll(observers.values()); 126 } 127 return observerList.iterator(); 128 } 129 130 133 public synchronized Object put(Object key, Object value) { 134 if (key instanceof BasicQuery) { 135 return put(((BasicQuery) key).getQuery(), (List) value); 136 } 137 138 return put((SearchQuery) key, (List) value); 139 } 140 141 144 public synchronized Object put(SearchQuery query, List queryResult) { 145 if (!checkCachePolicy(query)) return null; 146 147 List n = (List) super.get(query); 148 if (n == null) { 149 addObservers(query); 150 } 151 return super.put(query, queryResult); 152 } 153 154 160 public synchronized Object remove(Object key) { 161 Object result = super.remove(key); 162 163 if (result != null) { Iterator i = observers.values().iterator(); 165 while (i.hasNext()) { 166 Observer o = (Observer) i.next(); 167 o.stopObserving(key); 168 } 169 } 170 return result; 171 } 172 173 176 private void addObservers(SearchQuery query) { 177 MMBase.getMMBase(); 178 179 Iterator i = query.getSteps().iterator(); 180 while (i.hasNext()) { 181 Step step = (Step) i.next(); 182 String type = step.getTableName(); 187 188 Observer o = (Observer) observers.get(type); 189 if (o == null) { 190 o = new Observer(type); 191 synchronized(this){ 192 observers.put(type, o); 193 } 194 } 195 o.observe(query); 196 } 197 } 198 199 public String toString() { 200 return this.getClass().getName() + " " + getName(); 201 } 202 203 207 208 private class Observer implements NodeEventListener, RelationEventListener { 209 213 private Set cacheKeys = new HashSet(); 216 private String type; 217 218 223 private Observer(String type) { 224 this.type = type; 225 MMBase mmb = MMBase.getMMBase(); 226 if (mmb.getMMObject(type) == null) { 229 int builderNumber = mmb.getRelDef().getNumberByName(type); 230 String newType = mmb.getRelDef().getBuilder(builderNumber).getTableName(); 231 if (log.isDebugEnabled()) { 232 log.debug("replaced the type: " + type + " with type:" + newType); 233 } 234 type = newType; 235 } 236 mmb.addNodeRelatedEventsListener(type, this); 237 } 238 239 245 protected synchronized boolean observe(Object key) { 246 return cacheKeys.add(key); 248 } 249 250 253 protected synchronized boolean stopObserving(Object key) { 254 return cacheKeys.remove(key); 255 } 256 257 262 public void notify(RelationEvent event) { 263 nodeChanged(event); 264 } 265 266 271 public void notify(NodeEvent event) { 272 nodeChanged(event); 273 } 274 275 protected int nodeChanged(Event event) throws IllegalArgumentException { 276 if (log.isDebugEnabled()) { 277 log.debug("Considering " + event); 278 } 279 int evaluatedResults = cacheKeys.size(); 280 Set removeKeys = new HashSet(); 281 long startTime = System.currentTimeMillis(); 282 synchronized (QueryResultCache.this) { 283 Iterator i = cacheKeys.iterator(); 284 if (log.isDebugEnabled()) { 285 log.debug("Considering " + cacheKeys.size() + " objects in " + QueryResultCache.this.getName() + " for flush because of " + event); 286 } 287 while(i.hasNext()) { 288 SearchQuery key = (SearchQuery) i.next(); 289 290 boolean shouldRelease; 291 if(releaseStrategy.isEnabled()){ 292 if(event instanceof NodeEvent){ 293 shouldRelease = releaseStrategy.evaluate((NodeEvent)event, key, (List) get(key)).shouldRelease(); 294 } else if (event instanceof RelationEvent){ 295 shouldRelease = releaseStrategy.evaluate((RelationEvent)event, key, (List) get(key)).shouldRelease(); 296 } else { 297 log.error("event " + event.getClass() + " " + event + " is of unsupported type"); 298 shouldRelease = false; 299 } 300 } else { 301 shouldRelease = true; 302 } 303 304 if (shouldRelease) { 305 removeKeys.add(key); 306 i.remove(); 307 } 308 309 } 310 311 i = removeKeys.iterator(); 314 while(i.hasNext()) { 315 QueryResultCache.this.remove(i.next()); 316 } 317 } 318 if (log.isDebugEnabled()) { 319 log.debug(QueryResultCache.this.getName() + ": event analyzed in " + (System.currentTimeMillis() - startTime) + " milisecs. evaluating " + evaluatedResults + ". Flushed " + removeKeys.size()); 320 } 321 return removeKeys.size(); 322 } 323 324 public String toString() { 325 return "QueryResultCacheObserver for " + type + " watching " + cacheKeys.size() + " queries"; 326 } 327 328 public void clear() { 329 cacheKeys.clear(); 330 } 331 } 332 333 public void clear(){ 334 super.clear(); 335 releaseStrategy.clear(); 336 Iterator i = observers.values().iterator(); 337 while (i.hasNext()) { 338 Observer o = (Observer) i.next(); 339 o.clear(); 340 } 341 } 342 } 343 | Popular Tags |