Author: jonesde
Date: Sun Sep 9 01:13:25 2007
New Revision: 573956
URL: http://svn.apache.org/viewvc?rev=573956&view=rev
Log:
A few refinements to the deadlock retry test case, but the main part of this is
the actual implementation of the deadlock retry in the service engine, and the
implementation of that makes the deadlock test case pass now; this is a bit of
rework in some low level code so this needs some good testing beyond the few
general tests already done
Modified:
ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/GenericAsyncEngine.java
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/StandardJavaEngine.java
ofbiz/trunk/framework/service/src/org/ofbiz/service/job/JobManager.java
ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEngineTestServices.java
ofbiz/trunk/framework/service/testdef/data/ServiceDeadLockRetryAssertData.xml
Modified:
ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java?rev=573956&r1=573955&r2=573956&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
(original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/ServiceDispatcher.java
Sun Sep 9 01:13:25 2007
@@ -61,6 +61,7 @@
public static final String module = ServiceDispatcher.class.getName();
public static final int lruLogSize = 200;
+ public static final int LOCK_RETRIES = 3;
protected static final Map runLog = new LRUMap(lruLogSize);
protected static Map dispatchers = FastMap.newInstance();
@@ -246,7 +247,7 @@
context = FastMap.newInstance();
}
- // setup the result map
+ // setup the result map and other initial settings
Map result = FastMap.newInstance();
boolean isFailure = false;
boolean isError = false;
@@ -264,7 +265,7 @@
DispatchContext ctx = (DispatchContext) localContext.get(localName);
GenericEngine engine = this.getGenericEngine(modelService.engineName);
- // setup default IN values
+ // set IN attributes with default-value as applicable
modelService.updateDefaultValues(context, ModelService.IN_PARAM);
Map ecaContext = null;
@@ -283,80 +284,147 @@
// now start a new transaction
beganTrans =
TransactionUtil.begin(modelService.transactionTimeout);
}
- }
-
- // XAResource debugging
- if (beganTrans && TransactionUtil.debugResources) {
- DebugXaResource dxa = new DebugXaResource(modelService.name);
- try {
- dxa.enlist();
- } catch (Exception e) {
- Debug.logError(e, module);
+ // enlist for XAResource debugging
+ if (beganTrans && TransactionUtil.debugResources) {
+ DebugXaResource dxa = new
DebugXaResource(modelService.name);
+ try {
+ dxa.enlist();
+ } catch (Exception e) {
+ Debug.logError(e, module);
+ }
}
}
try {
- // setup global transaction ECA listeners to execute later
- if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-rollback", ctx,
context, result, isError, isFailure);
- if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-commit", ctx,
context, result, isError, isFailure);
-
- // pre-auth ECA
- if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "auth", ctx, context,
result, isError, isFailure);
-
- // check for pre-auth failure/errors
- isFailure = ServiceUtil.isFailure(result);
- isError = ServiceUtil.isError(result);
- context = checkAuth(localName, context, modelService);
- Object userLogin = context.get("userLogin");
+ int lockRetriesRemaining = LOCK_RETRIES;
+ boolean needsLockRetry = false;
+
+ do {
+ lockRetriesRemaining--;
+
+ // NOTE: general pattern here is to do everything up to
the main service call, and retry it all if
+ //needed because those will be part of the same
transaction and have been rolled back
+ // TODO: if there is an ECA called async or in a new
transaciton it won't get rolled back
+ //but will be called again, which means the service may
complete multiple times! that would be for
+ //pre-invoke and earlier events only of course
+
+
+ // setup global transaction ECA listeners to execute later
+ if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-rollback", ctx,
context, result, isError, isFailure);
+ if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "global-commit", ctx,
context, result, isError, isFailure);
+
+ // pre-auth ECA
+ if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "auth", ctx, context,
result, isError, isFailure);
+
+ // check for pre-auth failure/errors
+ isFailure = ServiceUtil.isFailure(result);
+ isError = ServiceUtil.isError(result);
+
+ //Debug.logInfo("After [" + modelService.name + "]
pre-auth ECA, before auth; isFailure=" + isFailure + ", isError=" + isError,
module);
- if (modelService.auth && userLogin == null) {
- throw new ServiceAuthException("User authorization is
required for this service: " + modelService.name + modelService.debugInfo());
- }
+ context = checkAuth(localName, context, modelService);
+ Object userLogin = context.get("userLogin");
- // pre-validate ECA
- if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "in-validate", ctx,
context, result, isError, isFailure);
+ if (modelService.auth && userLogin == null) {
+ throw new ServiceAuthException("User authorization is
required for this service: " + modelService.name + modelService.debugInfo());
+ }
- // check for pre-validate failure/errors
- isFailure = ServiceUtil.isFailure(result);
- isError = ServiceUtil.isError(result);
+ // pre-validate ECA
+ if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "in-validate", ctx,
context, result, isError, isFailure);
- // validate the context
- if (modelService.validate && !isError && !isFailure) {
- try {
- modelService.validate(context, ModelService.IN_PARAM,
locale);
- } catch (ServiceValidationException e) {
- Debug.logError(e, "Incoming context (in runSync : " +
modelService.name + ") does not match expected requirements", module);
- throw e;
+ // check for pre-validate failure/errors
+ isFailure = ServiceUtil.isFailure(result);
+ isError = ServiceUtil.isError(result);
+
+ //Debug.logInfo("After [" + modelService.name + "]
pre-in-validate ECA, before in-validate; isFailure=" + isFailure + ", isError="
+ isError, module);
+
+ // validate the context
+ if (modelService.validate && !isError && !isFailure) {
+ try {
+ modelService.validate(context,
ModelService.IN_PARAM, locale);
+ } catch (ServiceValidationException e) {
+ Debug.logError(e, "Incoming context (in runSync :
" + modelService.name + ") does not match expected requirements", module);
+ throw e;
+ }
}
- }
- // pre-invoke ECA
- if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "invoke", ctx, context,
result, isError, isFailure);
+ // pre-invoke ECA
+ if (eventMap != null)
ServiceEcaUtil.evalRules(modelService.name, eventMap, "invoke", ctx, context,
result, isError, isFailure);
- // check for pre-invoke failure/errors
- isFailure = ServiceUtil.isFailure(result);
- isError = ServiceUtil.isError(result);
-
- // ===== invoke the service =====
- if (!isError && !isFailure) {
- Map invokeResult = engine.runSync(localName, modelService,
context);
- engine.sendCallbacks(modelService, context, invokeResult,
GenericEngine.SYNC_MODE);
- if (invokeResult != null) {
- result.putAll(invokeResult);
- } else {
- Debug.logWarning("Service (in runSync : " +
modelService.name + ") returns null result", module);
+ // check for pre-invoke failure/errors
+ isFailure = ServiceUtil.isFailure(result);
+ isError = ServiceUtil.isError(result);
+
+ //Debug.logInfo("After [" + modelService.name + "]
pre-invoke ECA, before invoke; isFailure=" + isFailure + ", isError=" +
isError, module);
+
+ // ===== invoke the service =====
+ if (!isError && !isFailure) {
+ Map invokeResult = engine.runSync(localName,
modelService, context);
+ engine.sendCallbacks(modelService, context,
invokeResult, GenericEngine.SYNC_MODE);
+ if (invokeResult != null) {
+ result.putAll(invokeResult);
+ } else {
+ Debug.logWarning("Service (in runSync : " +
modelService.name + ") returns null result", module);
+ }
}
- }
-
- // re-check the errors/failures
- isFailure = ServiceUtil.isFailure(result);
- isError = ServiceUtil.isError(result);
+
+ // re-check the errors/failures
+ isFailure = ServiceUtil.isFailure(result);
+ isError = ServiceUtil.isError(result);
+
+ //Debug.logInfo("After [" + modelService.name + "] invoke;
isFailure=" + isFailure + ", isError=" + isError, module);
+
+ // crazy stuff here: see if there was a deadlock error and
if so retry... which we can ONLY do if we own the transaction!
+ if (beganTrans) {
+ // look for the string DEADLOCK in an upper-cased
error message; tested on: Derby, MySQL
+ // - Derby 10.2.2.0 deadlock string: "A lock could not
be obtained due to a deadlock"
+ // - MySQL TODO
+ // TODO need testing in other databases because they
all return different error messages for this!
+ String errMsg = ServiceUtil.getErrorMessage(result);
+ // NOTE DEJ20070908 are there other things we need to
check? I don't think so because these will
+ //be Entity Engine errors that will be caught and come
back in an error message... IFF the
+ //service is written to not ignore it of course!
+ if (errMsg != null &&
errMsg.toUpperCase().indexOf("DEADLOCK") >= 0) {
+ // it's a deadlock! retry...
+ String retryMsg = "RETRYING SERVICE [" +
modelService.name + "]: Deadlock error found in message [" + errMsg + "]; retry
[" + (LOCK_RETRIES - lockRetriesRemaining) + "] of [" + LOCK_RETRIES + "]";
+
+ // make sure the old transaction is rolled back,
and then start a new one
+
+ // if there is an exception in these things, let
the big overall thing handle it
+ TransactionUtil.rollback(beganTrans, retryMsg,
null);
+
+ beganTrans =
TransactionUtil.begin(modelService.transactionTimeout);
+ // enlist for XAResource debugging
+ if (beganTrans && TransactionUtil.debugResources) {
+ DebugXaResource dxa = new
DebugXaResource(modelService.name);
+ try {
+ dxa.enlist();
+ } catch (Exception e) {
+ Debug.logError(e, module);
+ }
+ }
+
+ if (!beganTrans) {
+ // just log and let things roll through, will
be considered an error and ECAs, etc will run according to that
+ Debug.logError("After rollback attempt for
lock retry did not begin a new transaction!", module);
+ } else {
+ needsLockRetry = true;
+
+ // reset state variables
+ result = FastMap.newInstance();
+ isFailure = false;
+ isError = false;
+
+ Debug.logWarning(retryMsg, module);
+ }
+ }
+ }
+ } while (needsLockRetry && lockRetriesRemaining > 0);
// create a new context with the results to pass to ECA
services; necessary because caller may reuse this context
ecaContext = FastMap.newInstance();
ecaContext.putAll(context);
-
// copy all results: don't worry parameters that aren't
allowed won't be passed to the ECA services
ecaContext.putAll(result);
@@ -413,10 +481,9 @@
} finally {
// if there was an error, rollback transaction, otherwise
commit
if (isError) {
- String errMsg = "Service Error [" + modelService.name +
"]: " + ServiceUtil.getErrorMessage(result);
- // try to log the error
+ String errMsg = "Error is Service [" + modelService.name +
"]: " + ServiceUtil.getErrorMessage(result);
Debug.logError(errMsg, module);
-
+
// rollback the transaction
try {
TransactionUtil.rollback(beganTrans, errMsg, null);
@@ -519,22 +586,20 @@
try {
if (service.useTransaction) {
beganTrans = TransactionUtil.begin(service.transactionTimeout);
-
// isolate the transaction if defined
if (service.requireNewTransaction && !beganTrans) {
parentTransaction = TransactionUtil.suspend();
// now start a new transaction
beganTrans =
TransactionUtil.begin(service.transactionTimeout);
}
- }
-
- // XAResource debugging
- if (beganTrans && TransactionUtil.debugResources) {
- DebugXaResource dxa = new DebugXaResource(service.name);
- try {
- dxa.enlist();
- } catch (Exception e) {
- Debug.logError(e, module);
+ // enlist for XAResource debugging
+ if (beganTrans && TransactionUtil.debugResources) {
+ DebugXaResource dxa = new DebugXaResource(service.name);
+ try {
+ dxa.enlist();
+ } catch (Exception e) {
+ Debug.logError(e, module);
+ }
}
}
@@ -548,8 +613,9 @@
context = checkAuth(localName, context, service);
Object userLogin = context.get("userLogin");
- if (service.auth && userLogin == null)
+ if (service.auth && userLogin == null) {
throw new ServiceAuthException("User authorization is
required for this service: " + service.name + service.debugInfo());
+ }
// pre-validate ECA
if (eventMap != null) ServiceEcaUtil.evalRules(service.name,
eventMap, "in-validate", ctx, context, result, isError, isFailure);
Modified:
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/GenericAsyncEngine.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/GenericAsyncEngine.java?rev=573956&r1=573955&r2=573956&view=diff
==============================================================================
---
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/GenericAsyncEngine.java
(original)
+++
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/GenericAsyncEngine.java
Sun Sep 9 01:13:25 2007
@@ -88,8 +88,6 @@
GenericValue jobV = null;
// Build the value object(s).
try {
- List toBeStored = new LinkedList();
-
// Create the runtime data
String dataId =
dispatcher.getDelegator().getNextSeqId("RuntimeData");
@@ -97,7 +95,7 @@
UtilMisc.toMap("runtimeDataId", dataId));
runtimeData.set("runtimeInfo",
XmlSerializer.serialize(context));
- toBeStored.add(runtimeData);
+ runtimeData.create();
// Get the userLoginId out of the context
String authUserLoginId = null;
@@ -122,9 +120,7 @@
}
jobV = dispatcher.getDelegator().makeValue("JobSandbox",
jFields);
- toBeStored.add(jobV);
- dispatcher.getDelegator().storeAll(toBeStored);
-
+ jobV.create();
} catch (GenericEntityException e) {
throw new GenericServiceException("Unable to create persisted
job", e);
} catch (SerializeException e) {
@@ -167,4 +163,3 @@
}
}
}
-
Modified:
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/StandardJavaEngine.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/StandardJavaEngine.java?rev=573956&r1=573955&r2=573956&view=diff
==============================================================================
---
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/StandardJavaEngine.java
(original)
+++
ofbiz/trunk/framework/service/src/org/ofbiz/service/engine/StandardJavaEngine.java
Sun Sep 9 01:13:25 2007
@@ -52,8 +52,9 @@
public Map runSync(String localName, ModelService modelService, Map
context) throws GenericServiceException {
Object result = serviceInvoker(localName, modelService, context);
- if (result == null || !(result instanceof Map))
+ if (result == null || !(result instanceof Map)) {
throw new GenericServiceException("Service did not return expected
result");
+ }
return (Map) result;
}
@@ -62,28 +63,33 @@
// static java service methods should be: public Map
methodName(DispatchContext dctx, Map context)
DispatchContext dctx = dispatcher.getLocalContext(localName);
- if (modelService == null)
+ if (modelService == null) {
Debug.logError("ERROR: Null Model Service.", module);
- if (dctx == null)
+ }
+ if (dctx == null) {
Debug.logError("ERROR: Null DispatchContext.", module);
- if (context == null)
+ }
+ if (context == null) {
Debug.logError("ERROR: Null Service Context.", module);
+ }
Class[] paramTypes = new Class[] {DispatchContext.class, Map.class};
Object[] params = new Object[] {dctx, context};
Object result = null;
// check the package and method names
- if (modelService.location == null || modelService.invoke == null)
+ if (modelService.location == null || modelService.invoke == null) {
throw new GenericServiceException("Cannot locate service to invoke
(location or invoke name missing)");
+ }
// get the classloader to use
ClassLoader cl = null;
- if (dctx == null)
+ if (dctx == null) {
cl = this.getClass().getClassLoader();
- else
+ } else {
cl = dctx.getClassLoader();
+ }
try {
Class c = cl.loadClass(this.getLocation(modelService));
Modified:
ofbiz/trunk/framework/service/src/org/ofbiz/service/job/JobManager.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/job/JobManager.java?rev=573956&r1=573955&r2=573956&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/job/JobManager.java
(original)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/job/JobManager.java Sun
Sep 9 01:13:25 2007
@@ -88,8 +88,9 @@
/** Queues a Job to run now. */
public void runJob(Job job) throws JobManagerException {
- if (job.isValid())
+ if (job.isValid()) {
jp.queueNow(job);
+ }
}
/** Returns the ServiceDispatcher. */
Modified:
ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEngineTestServices.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEngineTestServices.java?rev=573956&r1=573955&r2=573956&view=diff
==============================================================================
---
ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEngineTestServices.java
(original)
+++
ofbiz/trunk/framework/service/src/org/ofbiz/service/test/ServiceEngineTestServices.java
Sun Sep 9 01:13:25 2007
@@ -18,8 +18,11 @@
*/
package org.ofbiz.service.test;
+import java.util.List;
import java.util.Map;
+import javolution.util.FastList;
+
import org.ofbiz.base.util.Debug;
import org.ofbiz.base.util.UtilMisc;
import org.ofbiz.entity.GenericDelegator;
@@ -42,8 +45,18 @@
GenericResultWaiter threadAWaiter =
dispatcher.runAsyncWait("testServiceDeadLockRetryThreadA", null, false);
GenericResultWaiter threadBWaiter =
dispatcher.runAsyncWait("testServiceDeadLockRetryThreadB", null, false);
// make sure to wait for these to both finish to make sure results
aren't checked until they are done
- threadAWaiter.waitForResult();
- threadBWaiter.waitForResult();
+ Map threadAResult = threadAWaiter.waitForResult();
+ Map threadBResult = threadBWaiter.waitForResult();
+ List errorList = FastList.newInstance();
+ if (ServiceUtil.isError(threadAResult)) {
+ errorList.add("Error running testServiceDeadLockRetryThreadA:
" + ServiceUtil.getErrorMessage(threadAResult));
+ }
+ if (ServiceUtil.isError(threadBResult)) {
+ errorList.add("Error running testServiceDeadLockRetryThreadB:
" + ServiceUtil.getErrorMessage(threadBResult));
+ }
+ if (errorList.size() > 0) {
+ return ServiceUtil.returnError("Error(s) running sub-services
in testServiceDeadLockRetry", errorList, null, null);
+ }
} catch (Exception e) {
String errMsg = "Error running deadlock test services: " +
e.toString();
Debug.logError(e, errMsg, module);
@@ -59,7 +72,7 @@
try {
// grab entity SVCLRT_A by changing, then wait, then find and
change SVCLRT_B
GenericValue testingTypeA =
delegator.findByPrimaryKey("TestingType", UtilMisc.toMap("testingTypeId",
"SVCLRT_A"));
- testingTypeA.set("description", "New description for SVCLRT_A from
Thread A");
+ testingTypeA.set("description", "New description for SVCLRT_A");
testingTypeA.store();
// wait at least long enough for the other method to have locked
resource B
@@ -68,7 +81,7 @@
Debug.logInfo("In testServiceDeadLockRetryThreadA done with wait,
updating SVCLRT_B", module);
GenericValue testingTypeB =
delegator.findByPrimaryKey("TestingType", UtilMisc.toMap("testingTypeId",
"SVCLRT_B"));
- testingTypeB.set("description", "New description for SVCLRT_B from
Thread A");
+ testingTypeB.set("description", "New description for SVCLRT_B");
testingTypeB.store();
} catch (GenericEntityException e) {
String errMsg = "Entity Engine Exception running dead lock test
thread A: " + e.toString();
@@ -88,7 +101,7 @@
try {
// grab entity SVCLRT_B by changing, then wait, then change
SVCLRT_A
GenericValue testingTypeB =
delegator.findByPrimaryKey("TestingType", UtilMisc.toMap("testingTypeId",
"SVCLRT_B"));
- testingTypeB.set("description", "New description for SVCLRT_B from
Thread B");
+ testingTypeB.set("description", "New description for SVCLRT_B");
testingTypeB.store();
// wait at least long enough for the other method to have locked
resource B
@@ -97,7 +110,7 @@
Debug.logInfo("In testServiceDeadLockRetryThreadB done with wait,
updating SVCLRT_A", module);
GenericValue testingTypeA =
delegator.findByPrimaryKey("TestingType", UtilMisc.toMap("testingTypeId",
"SVCLRT_A"));
- testingTypeA.set("description", "New description for SVCLRT_A from
Thread B");
+ testingTypeA.set("description", "New description for SVCLRT_A");
testingTypeA.store();
} catch (GenericEntityException e) {
String errMsg = "Entity Engine Exception running dead lock test
thread B: " + e.toString();
@@ -119,8 +132,18 @@
GenericResultWaiter grabberWaiter =
dispatcher.runAsyncWait("testServiceLockWaitTimeoutRetryGrabber", null, false);
GenericResultWaiter waiterWaiter =
dispatcher.runAsyncWait("testServiceLockWaitTimeoutRetryWaiter", null, false);
// make sure to wait for these to both finish to make sure results
aren't checked until they are done
- grabberWaiter.waitForResult();
- waiterWaiter.waitForResult();
+ Map grabberResult = grabberWaiter.waitForResult();
+ Map waiterResult = waiterWaiter.waitForResult();
+ List errorList = FastList.newInstance();
+ if (ServiceUtil.isError(grabberResult)) {
+ errorList.add("Error running
testServiceLockWaitTimeoutRetryGrabber: " +
ServiceUtil.getErrorMessage(grabberResult));
+ }
+ if (ServiceUtil.isError(waiterResult)) {
+ errorList.add("Error running
testServiceLockWaitTimeoutRetryWaiter: " +
ServiceUtil.getErrorMessage(waiterResult));
+ }
+ if (errorList.size() > 0) {
+ return ServiceUtil.returnError("Error(s) running sub-services
in testServiceLockWaitTimeoutRetry", errorList, null, null);
+ }
} catch (Exception e) {
String errMsg = "Error running deadlock test services: " +
e.toString();
Debug.logError(e, errMsg, module);
@@ -206,7 +229,10 @@
Debug.logInfo("In testServiceLockWaitTimeoutRetryCantRecover
(grabber) just updated SVCLWTRTCR, running sub-service in own transaction",
module);
// timeout is 5 seconds so it is longer than the tx timeout for
this service, so will fail quickly; with this transaction keeping a lock on the
record and that one trying to get it, bam we cause the error
-
dispatcher.runSync("testServiceLockWaitTimeoutRetryCantRecoverWaiter", null, 5,
true);
+ Map waiterResult =
dispatcher.runSync("testServiceLockWaitTimeoutRetryCantRecoverWaiter", null, 5,
true);
+ if (ServiceUtil.isError(waiterResult)) {
+ return ServiceUtil.returnError("Error running
testServiceLockWaitTimeoutRetryCantRecoverWaiter", null, null, waiterResult);
+ }
Debug.logInfo("In testServiceLockWaitTimeoutRetryCantRecover
(grabber) successfully finished running sub-service in own transaction",
module);
} catch (GenericServiceException e) {
Modified:
ofbiz/trunk/framework/service/testdef/data/ServiceDeadLockRetryAssertData.xml
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/testdef/data/ServiceDeadLockRetryAssertData.xml?rev=573956&r1=573955&r2=573956&view=diff
==============================================================================
---
ofbiz/trunk/framework/service/testdef/data/ServiceDeadLockRetryAssertData.xml
(original)
+++
ofbiz/trunk/framework/service/testdef/data/ServiceDeadLockRetryAssertData.xml
Sun Sep 9 01:13:25 2007
@@ -19,6 +19,9 @@
-->
<entity-engine-xml>
<!-- assert data for service dead lock recovery test -->
- <TestingType testingTypeId="SVCLRT_A" description="New description for
SVCLRT_A from Thread B"/>
- <TestingType testingTypeId="SVCLRT_B" description="New description for
SVCLRT_B from Thread A"/>
+ <!-- NOTE we don't know which thread (A or B) these will be from because
that is a race condition thing decided by
+ the database about which transaction to terminate, and the terminated
one will be the one that re-tries and
+ make it into the database at the end. -->
+ <TestingType testingTypeId="SVCLRT_A" description="New description for
SVCLRT_A"/>
+ <TestingType testingTypeId="SVCLRT_B" description="New description for
SVCLRT_B"/>
</entity-engine-xml>