Issue Details (XML | Word | Printable)

Key: NUCCORE-1264
Type: Bug Bug
Status: Closed Closed
Resolution: Fixed
Priority: Minor Minor
Assignee: Unassigned
Reporter: Hooman Valibeigi
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
DataNucleus Core

Loss of all collection elements on add+remove when playing around with SCO wrapper of an object that was subsequently made HOLLOW

Created: 17/Aug/14 02:02 PM   Updated: Wednesday 08:02 PM   Resolved: Wednesday 08:02 PM
Component/s: Java Types, Persistence
Affects Version/s: 3.2.13
Fix Version/s: 4.1.0.m1

Datastore: PostgreSQL
Severity: Development


 Description  « Hide
I came across this situation where an add+remove operation on the same instance of collection causes all the elements of the collection to be removed.

Consider

class A
{
    Set<B> bs;

    // With getters and setters
}

And have already persisted an A (a1) with two Bs (b1, b2)

The following code causes all elements to be removed

Set<B> bs = a1.getBs();
B b3 = new B();
bs.add(b3);
bs.remove(b1);
pm.makePersistent(a1);

However the following code works fine. Results in 2 Bs (b2, b3) still in a1

B b3 = new B();
a1.getBs().add(b3);
a1.getBs().remove(b1);
pm.makePersistent(a1);

The difference is the number of times getBs() is called.

I will post a testcase later.

Sort Order: Ascending order - Click to sort in descending order
Hooman Valibeigi added a comment - 17/Aug/14 02:57 PM


Hooman Valibeigi added a comment - 24/Aug/14 01:58 PM
Hi Andy,

I know this is not the place to argue over project templating, however I had my own reasons not to follow the test-jdo template. You may find them justifiable

1- I run my tests in a main method (using Junit's TestRunner) instead of running them at mvn test phase. If an assertion fails it won't disrupt the compilation phase and I can always do 'mvn install' before actually running the tests. In fact my tests are also Junit 4 compatible.

2- I felt a need for multiple maven modules at some point and since then I kept using that structure to report bugs. One example was this http://www.datanucleus.org/servlet/jira/browse/NUCCORE-1234. It was necessary to have multiple maven modules to reproduce that bug.

3- I am more comfortable with hg than git in windows.

Andy Jefferson added a comment - 24/Aug/14 02:40 PM
If you are more comfortable with that format then fine ... you run the test, download the code from GitHub, and work out where the problem is, and provide a patch. That's how open source is supposed to work.

Hooman Valibeigi added a comment - 24/Aug/14 05:34 PM
If it makes a difference here is a testcase based on your template
https://github.com/hoomanv/nucrdbms-825

For NUCCORE-1234, my previous comment still applies. It's not something you can test with 'mvn test' that easy. It requires an osgi runtime. Maybe you can use my template for osgi tests from now on.

Hooman Valibeigi added a comment - 16/Oct/14 12:26 PM
Also affects version 4.0.2

Andy Jefferson added a comment - 19/Nov/14 10:17 AM
There are many ways of doing what you want, but you have to be aware of JDO object lifecycle state at all times. Your test ignores JDO lifecycle state when doing updates to the collection and so fails.

You do things non-transactional so after the operation it is like the commit of a transaction. Consequently the object goes to NONTRANS/HOLLOW state (since you don't have datanucleus.retainValues set). Meaning that all fields are nulled.

You then call a.getBs() so this initialises/loads the field in the NONTRANS A object. You then invoke an operation on it (bs.add(new B())). This will then mean that after that the object falls back to NONTRANS/HOLLOW state, and fields are nulled.

You then continue using the wrapper Set that is no longer applicable to the owner object (since the field was nulled). It is arguable what could be expected of any persistence solution here. Ignore any calls to that object, or exception are the only options IMHO; work to ignore all calls would be simple (what people currently would get if they said makeTransient and then continued playing with a collection wrapper), whilst work to throw exceptions would be significant (modify all wrappers).


The workarounds are very simple

Option 1 : just use retainValues=true (if you want to write code of the form you have there and be nontransactional then this is the easiest way of getting transparent persistence).

Option 2 : call the getter of a field (as you noted above).

Option 3 : use transactions so it is clearer where the boundaries are for accessing fields

Andy Jefferson added a comment - 26/Nov/14 08:02 PM
GitHub master will now unset the owner of any wrapper collection/map so any subsequent operations on that wrapper will not be applied to the datastore. The provided test will still not pass with that change but then, as said earlier, it ignores JDO lifecycle states in its assumptions.