Object property unexpectedly set to null through forceMergeWithSnapshot
-----------------------------------------------------------------------
Key: CAY-863
URL: https://issues.apache.org/cayenne/browse/CAY-863
Project: Cayenne
Issue Type: Bug
Components: Cayenne Core Library
Affects Versions: 1.2 [STABLE], 2.0 [STABLE], 3.0
Environment: Windows, Linux, PostgreSQL
Reporter: Martin Thelian
Assignee: Andrus Adamchik
Hi!
We have problems in our application in situations where multiple threads try to update the same object in parallel. Here are some simplified parts of our code:
01: public void updateUserPoints(String userID, int points) {
02: DataContext dc = DataContext.createDataContext();
03:
04: USR usr = this.getUserByID(userID, dc);
05: if (usr != null) {
06: int currpoints = usr.getPoints().intValue();
07: currpoints += points;
08: usr.setPoints(new Integer(currpoints));
09: dc.commitChanges();
10: }
11: }
12:
13: public void updateUser(final String userID) {
14: DataContext dc = DataContext.createDataContext();
15: USR usr = this.getUserByID(userID, dc);
16: if (usr == null) return;
17:
18: // Change some user data ....
19: [...]
20:
21: // commit changes
22: try {
23: dc.commitChanges();
24: } catch (CayenneRuntimeException e) {
25: dc.rollbackChanges();
26: }
27:
28: System.out.println(usr.getMbuser().getFirstname());
29: // ^^ throws a NullPointerException because Mbuser is
30: // unexpectedly null here!
31: }
32:
33: private USR getUserByID(String userID, DataContext dc) {
34: SelectQuery query = new SelectQuery(USR.class, ExpressionFactory.matchExp("userID", userID));
35: List<USR> users = dc.performQuery(query);
36: return (users == null || users.size() == 0) ? null : users.get(0);
37: }
Thread-A calls updateUserPoints(..), which just increments a simple integer value.
Thread-B calls updateUser(..), which reads and updates some data and writes it back to DB.
The concurrency problem sometimes occurs at line 29. Sometime it happens that a call to usr.getMbuser() unexpectedly returns null, even though this property is never explicitly deleted or set to null by us. There is a one-to-one relationship between the USR and MBuser object.
Some debugging has shown that the property is set to "null" by one of the EventDispatcher-Threads. Here is a Stacktrace:
Thread [EventDispatchThread-2] (Suspended (breakpoint at line 175 in USR))
USR.writeProperty(String, Object) line: 175
DataRowUtils.forceMergeWithSnapshot(ObjEntity, DataObject, DataRow) line: 270
ObjectStore.processUpdatedSnapshot(Object, DataRow) line: 1175
ObjectStore.processSnapshotEvent(SnapshotEvent) line: 819
ObjectStore.snapshotsChanged(SnapshotEvent) line: 804
GeneratedMethodAccessor107.invoke(Object, Object[]) line: not available
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 585
EventManager$NonBlockingInvocation(Invocation).fire(Object[]) line: 240
EventManager$InvocationDispatch.fire() line: 452
EventManager$DispatchThread.run() line: 499
Deactivating cayenne.DataDomain.sharedCache or inserting the following DataContextDelegate at line 15 helps to skip the problem, but that's not a proper solution for our application.
dc.setDelegate(new DataContextDelegate() {
public void finishedMergeChanges(DataObject object) { }
public void finishedProcessDelete(DataObject object) { }
public boolean shouldMergeChanges(DataObject object, DataRow snapshotInStore) {
if (object instanceof USR && ((USR)object).getUserID().equals(userID)) {
return false;
}
}
return true;
}
public boolean shouldProcessDelete(DataObject object) { return true; }
public Query willPerformGenericQuery(DataContext context, Query query) { return query; }
public Query willPerformQuery(DataContext context, Query query) { return query; }
public GenericSelectQuery willPerformSelect(DataContext context, GenericSelectQuery query) { return query; }
});
The above problem seems to occur in Cayenne 1.2, 2.X and 3.0.
-- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.
This archive was generated by hypermail 2.0.0 : Wed Sep 12 2007 - 09:49:21 EDT