1 10 package org.mmbase.cache; 11 12 import java.util.HashMap ; 13 import java.util.Map ; 14 15 import org.mmbase.bridge.*; 16 import org.mmbase.bridge.util.Queries; 17 import org.mmbase.core.event.NodeEvent; 18 import org.mmbase.core.event.Event; 19 import org.mmbase.core.event.NodeEventHelper; 20 import org.mmbase.core.event.RelationEvent; 21 import org.mmbase.module.core.*; 22 import org.mmbase.storage.search.AggregatedField; 23 import org.mmbase.storage.search.Step; 24 import org.mmbase.storage.search.implementation.BasicFieldValueConstraint; 25 import org.mmbase.storage.search.implementation.BasicLegacyConstraint; 26 import org.mmbase.tests.BridgeTest; 27 import org.mmbase.util.logging.Logger; 28 import org.mmbase.util.logging.Logging; 29 30 38 public class ReleaseStrategyTest extends BridgeTest { 39 40 static protected Cloud cloud = null; 41 42 static protected RelationManager posrelManager; 43 static protected NodeManager relDefManager; 44 static protected NodeManager typeRelManager; 45 static protected NodeManager insRelManager; 46 static protected NodeManager newsManager; 47 static protected NodeManager urlsManager; 48 static protected NodeManager peopelManager; 49 static protected NodeList createdNodes; 50 51 static protected ReleaseStrategy strategy; 52 53 protected Query twooStepQuery; 54 protected Query oneStepQuery; 55 56 57 private static final Logger log = Logging.getLoggerInstance(ReleaseStrategyTest.class); 58 59 protected final static String TEST_RELATION_ROLE = "test"; 60 protected final static String NEWS_TITLE = "title"; 61 protected final static String URLS_NAME = "name"; 62 63 protected static final int POSREL_POS = 0; 64 65 static protected Node newsNode; 66 67 static protected Node urlsNode; 68 69 static protected Relation posrelNode; 70 71 public ReleaseStrategyTest(String name){ 72 super(name); 73 } 74 75 76 79 public void setUp() throws Exception { 80 if (cloud == null) { 81 startMMBase(); 82 cloud = getCloud(); 83 84 try { 85 newsManager = cloud.getNodeManager("news"); 86 urlsManager = cloud.getNodeManager("urls"); 87 posrelManager = cloud.getRelationManager("posrel"); 88 relDefManager = cloud.getNodeManager("reldef"); 89 typeRelManager = cloud.getNodeManager("typerel"); 90 insRelManager = cloud.getNodeManager("insrel"); 91 peopelManager = cloud.getNodeManager("people"); 92 } catch(NotFoundException e){ 93 throw new Exception ("Test cases cannot be performed because " + e.getMessage() + " Please arrange this in your cloud before running this TestCase."); 94 } 95 strategy = new BetterStrategy(); 96 createdNodes = cloud.createNodeList(); 97 98 99 Node typerel = typeRelManager.createNode(); 101 typerel.setNodeValue("snumber", peopelManager); 102 typerel.setNodeValue("dnumber", urlsManager); 103 typerel.setNodeValue("rnumber", posrelManager); 104 typerel.commit(); 105 createdNodes.add(typerel); 106 107 109 newsNode = newsManager.createNode(); 110 newsNode.setStringValue("title", NEWS_TITLE); 111 newsNode.commit(); 112 createdNodes.add(newsNode); 113 114 urlsNode = urlsManager.createNode(); 115 urlsNode.setStringValue("name", URLS_NAME); 116 urlsNode.commit(); 117 createdNodes.add(urlsNode); 118 119 posrelNode = newsNode.createRelation(urlsNode, posrelManager); 120 posrelNode.setIntValue("pos", POSREL_POS); 121 posrelNode.commit(); 122 createdNodes.add(posrelNode); 123 124 } 125 } 126 127 130 public void testNodeEvent(){ 131 133 NodeEvent event = NodeEventHelper.createNodeEventInstance(newsNode, Event.TYPE_NEW, null); 134 Query q1 = Queries.createQuery(cloud, null, "people,posrel,urls", "urls.name", null, null, null, null, false); 135 136 assertFalse("a node event should not flush a query if it's type is not in the path", 137 strategy.evaluate(event, q1, null).shouldRelease()); 138 } 139 140 141 142 143 144 147 public void testRelationEvent(){ 148 149 RelationEvent relEvent = NodeEventHelper.createRelationEventInstance(posrelNode, Event.TYPE_NEW, null); 151 152 Query q1 = Queries.createQuery(cloud, null, "urls", "urls.name", null, null, null, null, false); 154 155 assertFalse("relation event should not flush query with one step", 156 strategy.evaluate(relEvent, q1, null).shouldRelease()); 157 158 Query q2 = Queries.createQuery(cloud, null, "people,posrel,urls", "urls.name", null, null, null, null, false); 160 Query q3 = Queries.createQuery(cloud, null, "news,sorted,urls", "news.title", null, null, null, null, false); 161 Query q4 = Queries.createQuery(cloud, null, "news,posrel,attachments", "news.title", null, null, null, null, false); 162 163 assertFalse("relation event of new relation between nodes in multi step query (where source does not match) should not be flushed", 164 strategy.evaluate(relEvent, q2, null).shouldRelease()); 165 assertFalse("relation event of new relation between nodes in multi step query (where role does not match) should not be flushed", 166 strategy.evaluate(relEvent, q3, null).shouldRelease()); 167 assertFalse("relation event of new relation between nodes in multi step query (where destinantion does not match) should not be flushed", 168 strategy.evaluate(relEvent, q4, null).shouldRelease()); 169 170 172 Query q4a = Queries.createQuery(cloud, null, "news,posrel,urls", "news.title", null, null, null, null, false); 173 Query q4b = Queries.createQuery(cloud, null, "urls,posrel,news", "news.title", null, null, null, null, false); 174 175 Query q4c = Queries.createQuery(cloud, null, "news,posrel,object", "news.title", null, null, null, null, false); 176 Query q4d = Queries.createQuery(cloud, null, "object,posrel,news", "news.title", null, null, null, null, false); 177 178 assertTrue("when path of query matches relation event, query should be flushed", 179 strategy.evaluate(relEvent, q4a, null).shouldRelease()); 180 assertTrue("when path of query matches relation event, query should be flushed, allso when source and relation are swapped", 181 strategy.evaluate(relEvent, q4b, null).shouldRelease()); 182 assertTrue("when path of query matches relation event, query should be flushed", 183 strategy.evaluate(relEvent, q4c, null).shouldRelease()); 184 assertTrue("when path of query matches relation event, query should be flushed, allso when source and relation are swapped", 185 strategy.evaluate(relEvent, q4d, null).shouldRelease()); 186 187 188 Query q5 = Queries.createQuery(cloud, null, "news,urls", "urls.name", null, null, null, null, false); 190 assertTrue("relation event of new relation between nodes in multi step query (where role is not specified and source and destination match) should be flushed", 191 strategy.evaluate(relEvent, q5, null).shouldRelease()); 192 Query q51 = Queries.createQuery(cloud, null, "news,object", "object.number", null, null, null, null, false); 193 assertTrue("relation event of new relation between nodes in multi step query (where role is not specified and source and destination match) should be flushed", 194 strategy.evaluate(relEvent, q51, null).shouldRelease()); 195 196 Query q6 = Queries.createQuery(cloud, null, "people,urls", "urls.name", null, null, null, null, false); 198 Query q7 = Queries.createQuery(cloud, null, "news,attachments", "news.title", null, null, null, null, false); 199 200 assertFalse("relation event of new relation between nodes in multi step query where is not specified (and source does not match) should not be flushed", 201 strategy.evaluate(relEvent, q6, null).shouldRelease()); 202 assertFalse("relation event of new relation between nodes in multi step query where is not specified (and destination does not match) should not be flushed", 203 strategy.evaluate(relEvent, q7, null).shouldRelease()); 204 205 } 206 207 208 209 210 211 212 public void testNewNode(){ 213 log.debug("method: testMultiStepQueryNewNode()"); 214 Query q1 = Queries.createQuery(cloud, null, "news,posrel,urls", "news.title,urls.name",null, null, null, null, false); 215 Query q2 = Queries.createQuery(cloud, null, "object,posrel,urls", "object.otype,urls.name",null, null, null, null, false); 216 Query q3 = Queries.createQuery(cloud, null, "news,posrel,object", "news.title,object.owner",null, null, null, null, false); 217 Query q4 = Queries.createQuery(cloud, null, "news,urls", "news.title,urls.name",null, null, null, null, false); 218 Query q5 = Queries.createQuery(cloud, null, "object,object2", "object.otype,object2.otype",null, null, null, null, false); 219 220 NodeEvent event = NodeEventHelper.createNodeEventInstance(newsNode, Event.TYPE_NEW, null); 222 assertFalse("node event of new node on multi step query should not release the query", strategy.evaluate(event, q1, null).shouldRelease()); 223 assertFalse("node event of new node on multi step query should not release the query", strategy.evaluate(event, q2, null).shouldRelease()); 224 assertFalse("node event of new node on multi step query should not release the query", strategy.evaluate(event, q3, null).shouldRelease()); 225 assertFalse("node event of new node on multi step query should not release the query", strategy.evaluate(event, q4, null).shouldRelease()); 226 assertFalse("node event of new node on multi step query should not release the query", strategy.evaluate(event, q5, null).shouldRelease()); 227 228 } 229 230 231 public void testNewRelation(){ 232 log.debug("method: testMultiStepQueryNewRelation()"); 233 Query q1 = Queries.createQuery(cloud, null, "news,posrel,urls", "news.title,urls.name",null, null, null, null, false); 234 Query q2 = Queries.createQuery(cloud, null, "object,posrel,urls", "object.otype,urls.name",null, null, null, null, false); 235 Query q3 = Queries.createQuery(cloud, null, "news,posrel,object", "news.title,object.owner",null, null, null, null, false); 236 Query q4 = Queries.createQuery(cloud, null, "news,urls", "news.title,urls.name",null, null, null, null, false); 237 Query q5 = Queries.createQuery(cloud, null, "object,object2", "object.otype,object2.otype",null, null, null, null, false); 238 239 NodeEvent event = NodeEventHelper.createNodeEventInstance(posrelNode, Event.TYPE_NEW, null); 241 assertFalse("node event of new relation node on multi step query should not release the query", strategy.evaluate(event, q1, null).shouldRelease()); 242 assertFalse("node event of new relation node on multi step query should not release the query", strategy.evaluate(event, q2, null).shouldRelease()); 243 assertFalse("node event of new relation node on multi step query should not release the query", strategy.evaluate(event, q3, null).shouldRelease()); 244 assertFalse("node event of new relation node on multi step query should not release the query", strategy.evaluate(event, q4, null).shouldRelease()); 245 assertFalse("node event of new relation node on multi step query should not release the query", strategy.evaluate(event, q5, null).shouldRelease()); 246 247 RelationEvent relEvent = NodeEventHelper.createRelationEventInstance(posrelNode, Event.TYPE_NEW, null); 249 assertTrue("relation event of new relation between nodes in multi step query should flush the cache", strategy.evaluate(relEvent, q1, null).shouldRelease()); 250 assertTrue("relation event of new relation between nodes in multi step query should flush the cache", strategy.evaluate(relEvent, q2, null).shouldRelease()); 251 assertTrue("relation event of new relation between nodes in multi step query should flush the cache", strategy.evaluate(relEvent, q3, null).shouldRelease()); 252 assertTrue("relation event of new relation between nodes in multi step query should flush the cache", strategy.evaluate(relEvent, q4, null).shouldRelease()); 253 assertTrue("relation event of new relation between nodes in multi step query should flush the cache", strategy.evaluate(relEvent, q5, null).shouldRelease()); 254 255 } 256 257 258 259 260 public void testChangedNode(){ 261 log.debug("method: testMultiStepQueryChangedNode()"); 262 263 265 268 NodeEvent event = new NodeEvent(null, "news", 0, getMap("title", "oldTitle"), getMap("title", "newtitle"), Event.TYPE_CHANGE); 269 NodeEvent event2 = new NodeEvent(null, "news", 0, getMap("owner", "oldOwner"), getMap("owner", "newowner"), Event.TYPE_CHANGE); 270 { 271 Query q1 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.number < 1000", null, null, null, false); 272 Query q2 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.title = 'hallo'", null, null, null, false); 273 Query q3 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.title", "news.number < 1000", null, null, null, false); 274 275 assertFalse("changed field is not used by query: it should not be flushed", 276 strategy.evaluate(event, q1, null).shouldRelease()); 277 assertTrue("changed field is in constraints section of query: it should be flushed", 278 strategy.evaluate(event, q2, null).shouldRelease()); 279 assertTrue("changed field is in select section of query: it should be flushed", 280 strategy.evaluate(event, q3, null).shouldRelease()); 281 } 282 { Query q1 = Queries.createQuery(cloud, null, "object,posrel,urls" ,"object.otype", "object.number < 1000", null, null, null, false); 284 Query q2 = Queries.createQuery(cloud, null, "object,posrel,urls" ,"object.otype", "object.owner = 'hallo'", null, null, null, false); 285 Query q3 = Queries.createQuery(cloud, null, "object,posrel,urls" ,"object.owner", "news.number < 1000", null, null, null, false); 286 287 assertFalse("changed field is not used by query: it should not be flushed", 288 strategy.evaluate(event2, q1, null).shouldRelease()); 289 assertTrue("changed field is in constraints section of query: it should be flushed", 290 strategy.evaluate(event2, q2, null).shouldRelease()); 291 assertTrue("changed field is in select section of query: it should be flushed", 292 strategy.evaluate(event2, q3, null).shouldRelease()); 293 } 294 Query q4 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.number < 1000 AND urls.name = 'hi'", null, null, null, false); 296 Query q5 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.title='something' AND urls.name = 'hi'", null, null, null, false); 297 298 assertFalse("changed field is not used by (composite) constraint: it should not be flushed", 299 strategy.evaluate(event, q4, null).shouldRelease()); 300 assertTrue("changed field is used by (composite) constraint: it should be flushed", 301 strategy.evaluate(event, q5, null).shouldRelease()); 302 303 Query q6 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", null, null, null, null, false); 305 q6.setConstraint(new BasicLegacyConstraint("news.number < 1000 AND urls.name = 'hi'")); 306 307 assertFalse("changed field is not used by (legacy) constraint: it should not be flushed", 308 strategy.evaluate(event, q6, null).shouldRelease()); 309 310 q6.setConstraint(new BasicLegacyConstraint("news.title='something' AND urls.name = 'hi'")); 311 312 assertTrue("changed field is used by (legacy) constraint: it should be flushed", 313 strategy.evaluate(event, q6, null).shouldRelease()); 314 315 319 Query q7; 320 Step newsStep; 321 q7 = cloud.createAggregatedQuery(); 322 newsStep = q7.addStep(newsManager); 323 AggregatedField titleField = q7.addAggregatedField(newsStep, newsManager.getField("title"), 2); 324 325 assertFalse("aggregate queries (type count) where the changed field(s) match the step(s) should not be flushed", 326 strategy.evaluate(event, q7, null).shouldRelease()); 327 328 q7.setConstraint(new BasicFieldValueConstraint(titleField, "disco")); 330 assertTrue("aggregate queries (type count) where the changed field(s) match the step(s) but there are constraints on the step(s) should be flushed", 331 strategy.evaluate(event, q7, null).shouldRelease()); 332 333 int[] aggregations = new int[] { 335 AggregatedField.AGGREGATION_TYPE_COUNT_DISTINCT, 336 AggregatedField.AGGREGATION_TYPE_GROUP_BY, 337 AggregatedField.AGGREGATION_TYPE_MAX, 338 AggregatedField.AGGREGATION_TYPE_MIN}; 339 for(int i = 0; i < aggregations.length; i++){ 340 q7 = cloud.createAggregatedQuery(); 341 newsStep = q7.addStep(newsManager); 342 q7.addAggregatedField(newsStep, newsManager.getField("title"),aggregations[i]); 343 344 assertTrue ("aggregate queries (type " + AggregatedField.AGGREGATION_TYPE_DESCRIPTIONS[i] + ") where the changed field(s) match the step(s) should be flushed", 345 strategy.evaluate(event, q7, null).shouldRelease()); 346 } 347 } 348 349 350 public void testChangedRelation(){ 351 353 MMObjectNode pos = MMBase.getMMBase().getBuilder( posrelNode.getNodeManager().getName() ).getNode(posrelNode.getNumber()); 356 pos.setValue("pos", new Integer (100)); 357 RelationEvent relEvent = NodeEventHelper.createRelationEventInstance(posrelNode, Event.TYPE_CHANGE, null); 359 360 Query q1 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.number < 10 ", null, null, null, false); 361 Query q2 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "posrel.pos < 10 ", null, null, null, false); 362 Query q3 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle,posrel.pos", "news.number < 10 ", null, null, null, false); 363 364 assertFalse("changed relation field is not used by query: it should not be flushed", 365 strategy.evaluate(relEvent, q1, null).shouldRelease()); 366 assertTrue("changed relation field is in constraints section of query: it should be flushed", 367 strategy.evaluate(relEvent, q2, null).shouldRelease()); 368 assertTrue("changed relation field is in select section of query: it should be flushed", 369 strategy.evaluate(relEvent, q3, null).shouldRelease()); 370 371 Query q4 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.number < 1000 AND urls.name = 'hi'", null, null, null, false); 373 Query q5 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "posrel.pos < 1 AND urls.name = 'hi'", null, null, null, false); 374 375 assertFalse("changed relation field is not used by (composite) constraint: it should not be flushed", 376 strategy.evaluate(relEvent, q4, null).shouldRelease()); 377 assertTrue("changed relation field is used by (composite) constraint: it should be flushed", 378 strategy.evaluate(relEvent, q5, null).shouldRelease()); 379 380 Query q6 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", null, null, null, null, false); 382 q6.setConstraint(new BasicLegacyConstraint("news.number < 1000 AND urls.name = 'hi'")); 383 384 assertFalse("changed relation field is not used by (legacy) constraint: it should not be flushed", 385 strategy.evaluate(relEvent, q6, null).shouldRelease()); 386 387 q6.setConstraint(new BasicLegacyConstraint("news.title='something' AND posrel.pos < 1")); 388 389 assertTrue("changed relation field is used by (legacy) constraint: it should be flushed", 390 strategy.evaluate(relEvent, q6, null).shouldRelease()); 391 392 } 393 394 public void testGetConstraintsforField(){ 395 Query q1 = Queries.createQuery(cloud, null, "news,posrel,urls", "news.number", "news.title = 'hallo'", null, null, null, false); 396 Query q2 = Queries.createQuery(cloud, null, "news,posrel,urls", "news.number", "news.subtitle = 'hallo'", null, null, null, false); 397 Query q3 = Queries.createQuery(cloud, null, "news,posrel,urls", "news.number", "news.title = 'hallo' AND news.subtitle='hi'", null, null, null, false); 398 Query q4 = Queries.createQuery(cloud, null, "news,posrel,urls", "news.number", null, null, null, null, false); 399 400 MMBase mmb = MMBase.getMMBase(); 401 MMObjectBuilder news = mmb.getBuilder("news"); 402 assertTrue("title field of news builder is in constraints", 403 ReleaseStrategy.getConstraintsForField("title", news, null, q1).size() == 1); 404 assertTrue("title field of news builder is not in constraints", 405 ReleaseStrategy.getConstraintsForField("title", news, null, q2).size() == 0); 406 assertTrue("title field of news builder is one of the constraints.", 407 ReleaseStrategy.getConstraintsForField("title", news, null, q3).size() == 1); 408 assertTrue("there are no constraints.", 409 ReleaseStrategy.getConstraintsForField("title", news, null, q4).size() == 0); 410 } 411 412 413 protected Node createRelDefNode(String role, int dir) { 414 Node reldef = relDefManager.createNode(); 416 reldef.setValue("sname", role); 417 reldef.setValue("dname", "d" + role ); 418 reldef.setValue("sguiname", role); 419 reldef.setValue("dguiname", "d" + role); 420 reldef.setIntValue("dir", dir); 421 reldef.setNodeValue("builder", insRelManager); 422 reldef.commit(); 423 createdNodes.add(reldef); 424 return reldef; 425 } 426 427 public void testSpeed() { 428 NodeEvent event = new NodeEvent(null, "news", 0, getMap("title", "oldTitle"), getMap("title", "newtitle"), Event.TYPE_CHANGE); 429 430 Query q1 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.number < 1000", null, null, null, false); 431 Query q2 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.subtitle", "news.title = 'hallo'", null, null, null, false); 432 Query q3 = Queries.createQuery(cloud, null, "news,posrel,urls" ,"news.title", "news.number < 1000", null, null, null, false); 433 434 435 ChainedReleaseStrategy chain = new ChainedReleaseStrategy(); chain.addReleaseStrategy(strategy); 437 System.out.println("Simple performance."); 438 long startTime = System.currentTimeMillis(); 439 for (int i = 0; i < 50000; i++) { 440 chain.evaluate(event, q1, null).shouldRelease(); 441 chain.evaluate(event, q2, null).shouldRelease(); 442 chain.evaluate(event, q3, null).shouldRelease(); 443 } 444 System.out.println("Simple performance test result: " + (System.currentTimeMillis() - startTime) + " ms"); 445 446 447 } 448 449 private Map getMap(Object key, Object value){ 450 Map m = new HashMap (); 451 m.put(key, value); 452 return m; 453 } 454 455 } 456 | Popular Tags |