Author: adrianc
Date: Fri Apr 26 17:04:49 2013
New Revision: 1476296
URL: http://svn.apache.org/r1476296
Log:
Some bug fixes for entity engine caches. GenericDelegator was inconsistent in
clearing caches - some methods cleared the cache before the entity operation
(wrong) while others cleared the cache after the entity operation (right).
Also, I updated the Delegator JavaDocs to warn against skipping the cache
clearing step - which shouldn't be done. Finally, the
AbstractEntityConditionCache.storeHook method doesn't work (for a number of
reasons) so I bypassed it.
Modified:
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/AbstractEntityConditionCache.java
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/Cache.java
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/eca/EntityEcaHandler.java
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java?rev=1476296&r1=1476295&r2=1476296&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java (original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/Delegator.java Fri Apr 26
17:04:49 2013
@@ -159,8 +159,9 @@ public interface Delegator {
* @param primaryKey
* The GenericPK to create a value in the datasource from
* @param doCacheClear
- * boolean that specifies whether to clear related cache entries
- * for this primaryKey to be created
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return GenericValue instance containing the new instance
*/
public GenericValue create(GenericPK primaryKey, boolean doCacheClear)
throws GenericEntityException;
@@ -183,7 +184,8 @@ public interface Delegator {
* The GenericValue to create a value in the datasource from
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return GenericValue instance containing the new instance
*/
public GenericValue create(GenericValue value, boolean doCacheClear)
throws GenericEntityException;
@@ -222,7 +224,8 @@ public interface Delegator {
* instance
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return GenericValue instance containing the new or updated instance
*/
public GenericValue createOrStore(GenericValue value, boolean
doCacheClear) throws GenericEntityException;
@@ -950,7 +953,8 @@ public interface Delegator {
* GenericValue instance containing the entity to refresh
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
*/
public void refresh(GenericValue value, boolean doCacheClear) throws
GenericEntityException;
@@ -999,7 +1003,8 @@ public interface Delegator {
* or by and fields to remove
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int removeAll(List<? extends GenericEntity> dummyPKs, boolean
doCacheClear) throws GenericEntityException;
@@ -1013,8 +1018,9 @@ public interface Delegator {
* @param entityName
* The Name of the Entity as defined in the entity XML file
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
this
- * value to be removed
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @param fields
* The fields of the named entity to query by with their
* corresponding values
@@ -1045,8 +1051,9 @@ public interface Delegator {
* The fields of the named entity to query by with their
* corresponding values
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
this
- * value to be removed
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int removeByAnd(String entityName, Map<String, ? extends Object>
fields, boolean doCacheClear) throws GenericEntityException;
@@ -1083,8 +1090,9 @@ public interface Delegator {
* @param condition
* The condition used to restrict the removing
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
this
- * value to be removed
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int removeByCondition(String entityName, EntityCondition condition,
boolean doCacheClear) throws GenericEntityException;
@@ -1104,8 +1112,9 @@ public interface Delegator {
* @param primaryKey
* The primary key of the entity to remove.
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
this
- * primaryKey to be removed
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int removeByPrimaryKey(GenericPK primaryKey, boolean doCacheClear)
throws GenericEntityException;
@@ -1135,8 +1144,9 @@ public interface Delegator {
* @param value
* GenericValue instance containing the entity
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
this
- * value to be removed
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int removeRelated(String relationName, GenericValue value, boolean
doCacheClear) throws GenericEntityException;
@@ -1156,8 +1166,9 @@ public interface Delegator {
* @param value
* The GenericValue object of the entity to remove.
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
this
- * value to be removed
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int removeValue(GenericValue value, boolean doCacheClear) throws
GenericEntityException;
@@ -1199,7 +1210,8 @@ public interface Delegator {
* GenericValue instance containing the entity
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int store(GenericValue value, boolean doCacheClear) throws
GenericEntityException;
@@ -1236,7 +1248,8 @@ public interface Delegator {
* store
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
*/
public int storeAll(List<GenericValue> values, boolean doCacheClear)
throws GenericEntityException;
@@ -1256,7 +1269,8 @@ public interface Delegator {
* store
* @param doCacheClear
* boolean that specifies whether or not to automatically clear
- * cache entries related to this operation
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @param createDummyFks
* boolean that specifies whether or not to automatically create
* "dummy" place holder FKs
@@ -1288,8 +1302,9 @@ public interface Delegator {
* @param condition
* The condition that restricts the list of stored values
* @param doCacheClear
- * boolean that specifies whether to clear cache entries for
- * these values
+ * boolean that specifies whether or not to automatically clear
+ * cache entries related to this operation. This should always
be
+ * <code>true</code> - otherwise you will lose data integrity.
* @return int representing number of rows effected by this operation
* @throws GenericEntityException
*/
Modified:
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java?rev=1476296&r1=1476295&r2=1476296&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java
(original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/GenericDelegator.java Fri
Apr 26 17:04:49 2013
@@ -995,12 +995,6 @@ public class GenericDelegator implements
GenericHelper helper = getEntityHelper(primaryKey.getEntityName());
- if (doCacheClear) {
- // always clear cache before the operation
- ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR,
EntityEcaHandler.OP_REMOVE, primaryKey, false);
- this.clearCacheLine(primaryKey);
- }
-
ecaRunner.evalRules(EntityEcaHandler.EV_RUN,
EntityEcaHandler.OP_REMOVE, primaryKey, false);
// if audit log on for any fields, save old value before removing
so it's still there
@@ -1013,6 +1007,11 @@ public class GenericDelegator implements
removedEntity = this.findOne(primaryKey.getEntityName(),
primaryKey, false);
}
int num = helper.removeByPrimaryKey(primaryKey);
+ if (doCacheClear) {
+ ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR,
EntityEcaHandler.OP_REMOVE, primaryKey, false);
+ this.clearCacheLine(primaryKey);
+ }
+
this.saveEntitySyncRemoveInfo(primaryKey);
if (testMode) {
@@ -1064,11 +1063,6 @@ public class GenericDelegator implements
GenericHelper helper = getEntityHelper(value.getEntityName());
- if (doCacheClear) {
- ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR,
EntityEcaHandler.OP_REMOVE, value, false);
- this.clearCacheLine(value);
- }
-
ecaRunner.evalRules(EntityEcaHandler.EV_RUN,
EntityEcaHandler.OP_REMOVE, value, false);
// if audit log on for any fields, save old value before actual
remove
@@ -1084,6 +1078,11 @@ public class GenericDelegator implements
int num = helper.removeByPrimaryKey(value.getPrimaryKey());
// Need to call removedFromDatasource() here because the helper
calls removedFromDatasource() on the PK instead of the GenericEntity.
value.removedFromDatasource();
+ if (doCacheClear) {
+ ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR,
EntityEcaHandler.OP_REMOVE, value, false);
+ this.clearCacheLine(value);
+ }
+
if (testMode) {
if (removedValue != null) {
@@ -1329,12 +1328,6 @@ public class GenericDelegator implements
ecaRunner.evalRules(EntityEcaHandler.EV_VALIDATE,
EntityEcaHandler.OP_STORE, value, false);
GenericHelper helper = getEntityHelper(value.getEntityName());
- if (doCacheClear) {
- // always clear cache before the operation
- ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR,
EntityEcaHandler.OP_STORE, value, false);
- this.clearCacheLine(value);
- }
-
ecaRunner.evalRules(EntityEcaHandler.EV_RUN,
EntityEcaHandler.OP_STORE, value, false);
this.encryptFields(value);
@@ -1350,6 +1343,10 @@ public class GenericDelegator implements
}
int retVal = helper.store(value);
+ if (doCacheClear) {
+ ecaRunner.evalRules(EntityEcaHandler.EV_CACHE_CLEAR,
EntityEcaHandler.OP_STORE, value, false);
+ this.clearCacheLine(value);
+ }
if (testMode) {
storeForTestRollback(new TestOperation(OperationType.UPDATE,
updatedEntity));
@@ -2192,11 +2189,6 @@ public class GenericDelegator implements
* @see
org.ofbiz.entity.Delegator#clearCacheLine(org.ofbiz.entity.GenericValue,
boolean)
*/
public void clearCacheLine(GenericValue value, boolean distribute) {
- // TODO: make this a bit more intelligent by passing in the operation
being done (create, update, remove) so we can not do unnecessary cache clears...
- // for instance:
- // on create don't clear by primary cache (and won't clear original
values because there won't be any)
- // on remove don't clear by and for new values, but do for original
values
-
// Debug.logInfo("running clearCacheLine for value: " + value + ",
distribute: " + distribute, module);
if (value == null) {
return;
Modified:
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/AbstractEntityConditionCache.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/AbstractEntityConditionCache.java?rev=1476296&r1=1476295&r2=1476296&view=diff
==============================================================================
---
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/AbstractEntityConditionCache.java
(original)
+++
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/AbstractEntityConditionCache.java
Fri Apr 26 17:04:49 2013
@@ -59,6 +59,21 @@ public abstract class AbstractEntityCond
return conditionCache.put(key, value);
}
+ /**
+ * Removes all condition caches that include the specified entity.
+ */
+ public void remove(GenericEntity entity) {
+ UtilCache.clearCache(getCacheName(entity.getEntityName()));
+ ModelEntity model = entity.getModelEntity();
+ if (model != null) {
+ Iterator<String> it = model.getViewConvertorsIterator();
+ while (it.hasNext()) {
+ String targetEntityName = it.next();
+ UtilCache.clearCache(getCacheName(targetEntityName));
+ }
+ }
+ }
+
public void remove(String entityName, EntityCondition condition) {
UtilCache<EntityCondition, ConcurrentMap<K, V>> cache =
getCache(entityName);
if (cache == null) return;
Modified: ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/Cache.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/Cache.java?rev=1476296&r1=1476295&r2=1476296&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/Cache.java
(original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/cache/Cache.java Fri Apr
26 17:04:49 2013
@@ -112,16 +112,22 @@ public class Cache {
public GenericValue remove(GenericEntity entity) {
if (Debug.verboseOn()) Debug.logVerbose("Cache remove GenericEntity: "
+ entity, module);
GenericValue oldEntity = entityCache.remove(entity.getPrimaryKey());
- entityListCache.storeHook(entity, null);
- entityObjectCache.storeHook(entity, null);
+ // Workaround because AbstractEntityConditionCache.storeHook doesn't
work.
+ entityListCache.remove(entity);
+ entityObjectCache.remove(entity);
+ // entityListCache.storeHook(entity, null);
+ // entityObjectCache.storeHook(entity, null);
return oldEntity;
}
public GenericValue remove(GenericPK pk) {
if (Debug.verboseOn()) Debug.logVerbose("Cache remove GenericPK: " +
pk, module);
GenericValue oldEntity = entityCache.remove(pk);
- entityListCache.storeHook(pk, null);
- entityObjectCache.storeHook(pk, null);
+ // Workaround because AbstractEntityConditionCache.storeHook doesn't
work.
+ entityListCache.remove(pk);
+ entityObjectCache.remove(pk);
+ // entityListCache.storeHook(pk, null);
+ // entityObjectCache.storeHook(pk, null);
return oldEntity;
}
}
Modified:
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/eca/EntityEcaHandler.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/eca/EntityEcaHandler.java?rev=1476296&r1=1476295&r2=1476296&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/eca/EntityEcaHandler.java
(original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/eca/EntityEcaHandler.java
Fri Apr 26 17:04:49 2013
@@ -34,6 +34,9 @@ public interface EntityEcaHandler<T> {
public static final String EV_VALIDATE = "validate";
public static final String EV_RUN = "run";
public static final String EV_RETURN = "return";
+ /**
+ * Invoked after the entity operation, but before the cache is cleared.
+ */
public static final String EV_CACHE_CLEAR = "cache-clear";
public static final String EV_CACHE_CHECK = "cache-check";
public static final String EV_CACHE_PUT = "cache-put";
Modified:
ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java?rev=1476296&r1=1476295&r2=1476296&view=diff
==============================================================================
--- ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
(original)
+++ ofbiz/trunk/framework/entity/src/org/ofbiz/entity/test/EntityTestSuite.java
Fri Apr 26 17:04:49 2013
@@ -107,7 +107,7 @@ public class EntityTestSuite extends Ent
observer.arg = null;
GenericValue clonedValue = (GenericValue) testValue.clone();
clonedValue.put("description", "New Testing Type #1");
- assertTrue("Observable has changed", testValue.hasChanged());
+ assertTrue("Cloned Observable has changed", clonedValue.hasChanged());
assertEquals("Observer called with cloned GenericValue field name",
"description", observer.arg);
// now store it
testValue.store();
@@ -142,12 +142,11 @@ public class EntityTestSuite extends Ent
*/
public void testEntityCache() throws Exception {
// Test primary key cache
- GenericValue testValue = delegator.findOne("TestingType", true, "testingTypeId",
"TEST-2");
- assertEquals("Retrieved from cache value has the correct description", "Testing Type
#2", testValue.getString("description"));
+ GenericValue testValue = delegator.findOne("TestingType", true, "testingTypeId",
"TEST-3");
+ assertEquals("Retrieved from cache value has the correct description", "Testing Type
#3", testValue.getString("description"));
// Test immutable
try {
- testValue.put("description", "New Testing Type #2");
- testValue.store();
+ testValue.put("description", "New Testing Type #3");
fail("Modified an immutable GenericValue");
} catch (IllegalStateException e) {
}
@@ -156,6 +155,17 @@ public class EntityTestSuite extends Ent
fail("Modified an immutable GenericValue");
} catch (UnsupportedOperationException e) {
}
+ // Test entity value update operation updates the cache
+ testValue = (GenericValue) testValue.clone();
+ testValue.put("description", "New Testing Type #3");
+ testValue.store();
+ testValue = delegator.findOne("TestingType", true, "testingTypeId",
"TEST-3");
+ assertEquals("Retrieved from cache value has the correct description", "New Testing
Type #3", testValue.getString("description"));
+ // Test entity value remove operation updates the cache
+ testValue = (GenericValue) testValue.clone();
+ testValue.remove();
+ testValue = delegator.findOne("TestingType", true, "testingTypeId",
"TEST-3");
+ assertEquals("Retrieved from cache value is null", null, testValue);
// Test entity condition cache
EntityCondition testCondition = EntityCondition.makeCondition("description",
EntityOperator.EQUALS, "Testing Type #2");
List<GenericValue> testList = delegator.findList("TestingType",
testCondition, null, null, null, true);
@@ -165,7 +175,6 @@ public class EntityTestSuite extends Ent
// Test immutable
try {
testValue.put("description", "New Testing Type #2");
- testValue.store();
fail("Modified an immutable GenericValue");
} catch (IllegalStateException e) {
}
@@ -174,13 +183,24 @@ public class EntityTestSuite extends Ent
fail("Modified an immutable GenericValue");
} catch (UnsupportedOperationException e) {
}
- /* Commenting this out for now because the tests fail due to flaws in
the EntityListCache implementation.
+ // Test entity value create operation updates the cache
testValue = (GenericValue) testValue.clone();
+ testValue.put("testingTypeId", "TEST-9");
+ testValue.create();
+ testList = delegator.findList("TestingType", testCondition, null,
null, null, true);
+ assertEquals("Delegator findList returned two values", 2,
testList.size());
+ // Test entity value update operation updates the cache
testValue.put("description", "New Testing Type #2");
testValue.store();
testList = delegator.findList("TestingType", testCondition, null,
null, null, true);
+ assertEquals("Delegator findList returned one value", 1,
testList.size());
+ // Test entity value remove operation updates the cache
+ testValue = testList.get(0);
+ testValue = (GenericValue) testValue.clone();
+ testValue.remove();
+ testList = delegator.findList("TestingType", testCondition, null,
null, null, true);
assertEquals("Delegator findList returned empty list", 0,
testList.size());
- */
+ // TODO: Test view entities.
}
/*