Index: src/test/java/org/drools/common/LazyTMSEnablingTest.java =================================================================== --- src/test/java/org/drools/common/LazyTMSEnablingTest.java (revision 0) +++ src/test/java/org/drools/common/LazyTMSEnablingTest.java (revision 0) @@ -0,0 +1,131 @@ +/* + * Copyright 2010 JBoss Inc + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.drools.common; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.drools.RuleBaseFactory; +import org.drools.reteoo.ObjectTypeConf; +import org.drools.reteoo.ReteooWorkingMemory; +import org.junit.Before; +import org.junit.Test; + +/** + *
+ * Verify that TMS will be lazily enabled after the first logical insert is + * processed. + *
+ * + *+ * This is based on the ideas + * published here. + *
+ * + * @author Leonardo Gomes + */ +public class LazyTMSEnablingTest { + + private ReteooWorkingMemory wm; + private TruthMaintenanceSystem tms; + + @Before + public void setUp() { + + wm = (ReteooWorkingMemory) RuleBaseFactory.newRuleBase() + .newStatefulSession(); + + tms = wm.getTruthMaintenanceSystem(); + + } + + @Test + public void shouldLazilyAdd() throws Exception { + + final String fact1 = "logical"; + + wm.insert(fact1); + + assertEquals( + "Shouldn't have anything, since no logical insert was performed.", + 0, tms.getAssertMap().size()); + + final String fact2 = "logical"; + + wm.insertLogical(fact2); + + assertEquals( + "Now that a logical insert was done, it should have an element.", + 1, tms.getAssertMap().size()); + + // Make sure the internals are fine. + ObjectTypeConf typeConf = wm.getObjectTypeConfigurationRegistry() + .getObjectTypeConf(wm.getEntryPoint(), fact1); + + assertTrue("Should have enabled TMS", typeConf.isTMSEnabled()); + + } + + @Test + public void shouldEnableTMSForSpecificType() throws Exception { + + final String stringFact1 = "toto"; + final String stringFact2 = "toto"; + final String anotherString = "tata"; + + final Integer intFact1 = 99; + final Integer intFact2 = 99; + + final Double doubleFact = 77.8; + + ObjectTypeConf stringTypeConf = wm.getObjectTypeConfigurationRegistry() + .getObjectTypeConf(wm.getEntryPoint(), stringFact1); + + ObjectTypeConf intTypeConf = wm.getObjectTypeConfigurationRegistry() + .getObjectTypeConf(wm.getEntryPoint(), intFact1); + + wm.insert(stringFact1); + wm.insert(anotherString); + wm.insert(intFact1); + wm.insert(doubleFact); + + for (ObjectTypeConf conf : wm.getObjectTypeConfigurationRegistry() + .values()) { + + assertFalse( + "TMS shouldn't be enabled for any type, since no logical insert was done.", + conf.isTMSEnabled()); + + } + + wm.insertLogical(stringFact2); + + assertTrue("Should have enabled TMS for Strings.", stringTypeConf + .isTMSEnabled()); + + assertFalse("Shouldn't have enabled TMS for Integers.", intTypeConf + .isTMSEnabled()); + + wm.insertLogical(intFact2); + + assertTrue("Now it should have enabled TMS for Integers!.", intTypeConf + .isTMSEnabled()); + + } + +} Index: src/test/java/org/drools/reteoo/ReteooWorkingMemoryTest.java =================================================================== --- src/test/java/org/drools/reteoo/ReteooWorkingMemoryTest.java (revision 35290) +++ src/test/java/org/drools/reteoo/ReteooWorkingMemoryTest.java (working copy) @@ -50,10 +50,14 @@ final ReteooWorkingMemory workingMemory = (ReteooWorkingMemory) RuleBaseFactory.newRuleBase().newStatefulSession(); final TruthMaintenanceSystem tms = workingMemory.getTruthMaintenanceSystem(); final String string = "test"; - FactHandle fd = workingMemory.insert( string ); + + workingMemory.insert( string ); + + FactHandle fd = workingMemory.insertLogical( string ); assertEquals( 1, tms.getAssertMap().size() ); + EqualityKey key = tms.get( string ); assertSame( fd, key.getFactHandle() ); Index: src/main/java/org/drools/common/AbstractWorkingMemory.java =================================================================== --- src/main/java/org/drools/common/AbstractWorkingMemory.java (revision 35290) +++ src/main/java/org/drools/common/AbstractWorkingMemory.java (working copy) @@ -52,9 +52,11 @@ import org.drools.RuleBaseConfiguration.AssertBehaviour; import org.drools.RuleBaseConfiguration.LogicalOverride; import org.drools.base.CalendarsImpl; +import org.drools.base.ClassObjectType; import org.drools.base.MapGlobalResolver; import org.drools.concurrent.ExecutorService; import org.drools.concurrent.ExternalExecutorService; +import org.drools.core.util.ObjectHashSet; import org.drools.event.AgendaEventListener; import org.drools.event.AgendaEventSupport; import org.drools.event.RuleBaseEventListener; @@ -68,9 +70,10 @@ import org.drools.reteoo.LIANodePropagation; import org.drools.reteoo.LeftTuple; import org.drools.reteoo.ObjectTypeConf; +import org.drools.reteoo.ObjectTypeNode; import org.drools.reteoo.PartitionManager; import org.drools.reteoo.PartitionTaskManager; -import org.drools.reteoo.ReteooWorkingMemory; +import org.drools.reteoo.Rete; import org.drools.rule.Declaration; import org.drools.rule.EntryPoint; import org.drools.rule.Rule; @@ -93,6 +96,7 @@ import org.drools.spi.AsyncExceptionHandler; import org.drools.spi.FactHandleFactory; import org.drools.spi.GlobalResolver; +import org.drools.spi.ObjectType; import org.drools.spi.PropagationContext; import org.drools.time.SessionClock; import org.drools.time.TimerService; @@ -169,7 +173,6 @@ */ protected AtomicLong propagationIdCounter; - private boolean maintainTms; private boolean sequential; private List liaPropagations; @@ -319,9 +322,9 @@ final RuleBaseConfiguration conf = this.ruleBase.getConfiguration(); - this.maintainTms = conf.isMaintainTms(); this.sequential = conf.isSequential(); + if ( initialFactHandle == null ) { this.initialFactHandle = handleFactory.newFactHandle( InitialFactImpl.getInstance(), null, @@ -345,13 +348,9 @@ timerService = TimerServiceFactory.getTimerService( this.config ); this.nodeMemories = new ConcurrentNodeMemories( this.ruleBase ); + + this.tms = new TruthMaintenanceSystem(this); - if ( this.maintainTms ) { - this.tms = new TruthMaintenanceSystem( this ); - } else { - this.tms = null; - } - this.propagationIdCounter = new AtomicLong( propagationContext ); this.objectStore = new SingleThreadedObjectStore( conf, @@ -953,6 +952,9 @@ ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint, object ); + if ( logical && !typeConf.isTMSEnabled()) { + enableTMS(object, typeConf); + } InternalFactHandle handle = null; @@ -972,8 +974,8 @@ // check if the object already exists in the WM handle = (InternalFactHandle) this.objectStore.getHandleForObject( object ); - if ( this.maintainTms ) { - + if ( typeConf.isTMSEnabled() ) { + EqualityKey key = null; if ( handle == null ) { @@ -1006,12 +1008,14 @@ // At this point we know the handle is null if ( key == null ) { + handle = createHandle( object, typeConf ); - key = new EqualityKey( handle ); - handle.setEqualityKey( key ); + key = createEqualityKey(handle); + this.tms.put( key ); + if ( !logical ) { key.setStatus( EqualityKey.STATED ); } else { @@ -1110,6 +1114,53 @@ } + /** Side-effects, will add the created key to the handle. */ + private EqualityKey createEqualityKey(InternalFactHandle handle) { + EqualityKey key = new EqualityKey( handle ); + handle.setEqualityKey( key ); + return key; + } + + /** + * TMS will be automatically enabled when the first logical insert happens. + * + * We will take all the already asserted objects of the same type and initialize + * the equality map. + * + * @param object the logically inserted object. + * @param conf the type's configuration. + */ + private void enableTMS(Object object, ObjectTypeConf conf) { + + + final Rete source = this.ruleBase.getRete(); + final ClassObjectType cot = new ClassObjectType( object.getClass() ); + final Map