cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrus Adamchik <and...@objectstyle.org>
Subject Re: timing issue?
Date Wed, 21 Jul 2010 08:11:53 GMT
Hi Bryan,

There can definitely be a small delay updating a peer context in the  
same JVM with the commit data. And this is probably what you are  
observing in the test (adding a delay gives all DataContexts a chance  
to digest the event). If the relationship hasn't been refreshed for an  
hour, this is caused by something else... My guess is that the Company  
object in a peer context had modifications of its own, so Cayenne  
bailed on merging the changes into it. There is a code in ObjectStore  
responsible for merging to-many:

void processIndirectlyModifiedIDs(Collection indirectlyModifiedIDs) {
        Iterator indirectlyModifiedIt =  
indirectlyModifiedIDs.iterator();
        while (indirectlyModifiedIt.hasNext()) {
            ObjectId oid = (ObjectId) indirectlyModifiedIt.next();

            // access object map directly - the method should be  
called in a synchronized
            // context...
            final DataObject object = (DataObject) objectMap.get(oid);

            if (object == null
                    || object.getPersistenceState() !=  
PersistenceState.COMMITTED) {
                continue;
            }
....
}

One possible way around it is to invalidate Company object after  
commit (then on next read it will refetch its relationship).

Andrus

On Jul 20, 2010, at 4:05 PM, Bryan Lewis wrote:

> We released a new internal web app at the start of the month and we've
> noticed some troublesome behavior.  After the insertion or deletion  
> of an
> object, a to-many relationship can occasionally get out of sync.  For
> example, we have a Company entity with a to-many relationship to  
> Task. After
> the user adds a task and returns to the task list page, the new object
> doesn't appear.  Sometimes.  I've been working around it by adding  
> explicit
> refetches in the list pages.
>
> I've tried to boil it down to a reproducible test case.  The code  
> below
> simply adds and deletes a thousand objects and checks that the size  
> of the
> list is correct in a different DataContext.  One of the assertions  
> will fail
> at some point in the test.  I tried it with and without OSCache and  
> the
> error happens with both.
>
> I wondered if it might be some kind of timing issue.  If I added a
> one-second pause whenever the lists disagreed, that was enough to  
> get them
> back in sync.
>
> I'm not sure this completely explains the behavior we've been  
> seeing. We
> haven't been hitting the database that hard, with only about a half- 
> dozen
> users at any one time.  Yesterday we had a case where one user's  
> insertion
> didn't appear in another user's list almost an hour later.  It's a  
> start for
> discussion.  It would be good news if I'm missing something.
>
>
>   private static final int cRuns = 1000;
>
>   private Employee user;
>   private RDTaskType taskType;
>
>   private org.apache.cayenne.access.DataContext createDataContext()
>   {
>       Configuration config = Configuration.getSharedConfiguration();
>       DataDomain domain = config.getDomain();
>       return domain.createDataContext();
>   }
>
>   void onActionFromTestCaching()
>   {
>       DataContext dc = createDataContext();
>       DataContext dc2 = createDataContext();
>
>       // Get a few objects needed to populate new tasks.
>       user = DataObjectUtils.objectForPK(dc, Employee.class, 312);
>       taskType = DataObjectUtils.objectForPK(dc, RDTaskType.class,
> "CLIOR");
>
>       // A Company is the source of the to-many relationship.  Get the
> same
>       // one in two DataContexts.
>       Company company = DataObjectUtils.objectForPK(dc, Company.class,
> 5000);
>       Company company2 = (Company)  
> dc2.localObject(company.getObjectId(),
> null);
>
>       int nTasksStart = company.getTasks().size();
>
>       for (int i = 0; i < cRuns; i++) {
>           int nTasks = company.getTasks().size();
>           assert nTasks == nTasksStart + i : nTasks;
>
>           int nTasks2 = company2.getTasks().size();
>           if (nTasks2 != nTasks) {
>               debug("nTasks2 was " + nTasks2);
>               pause();
>               nTasks2 = company2.getTasks().size();
>               debug("nTasks2 now " + nTasks2);
>           }
>           assert nTasks2 == nTasks : "nTasks = " + nTasks + ",  
> nTasks2 = "
> + nTasks2; // sometimes fails
>
>           insertTask(company);
>       }
>
>       List<Task> tasks = company.getTasks();
>       nTasksStart = tasks.size();
>
>       for (int i = 0; i < cRuns; i++) {
>           int nTasks = company.getTasks().size();
>           assert nTasks == nTasksStart - i : nTasks;
>
>           int nTasks2 = company2.getTasks().size();
>           if (nTasks2 != nTasks) {
>               debug("nTasks2 was " + nTasks2);
>               pause();
>               nTasks2 = company2.getTasks().size();
>               debug("nTasks2 now " + nTasks2);
>           }
>           assert nTasks2 == nTasks : "nTasks = " + nTasks + ",  
> nTasks2 = "
> + nTasks2;
>
>           deleteTask(tasks.get(nTasks - 1));
>       }
>   }
>
>   private org.apache.cayenne.access.DataContext createDataContext()
>   {
>       Configuration config = Configuration.getSharedConfiguration();
>       DataDomain domain = config.getDomain();
>       return domain.createDataContext();
>   }
>
>   private void insertTask(Company company)
>   {
>       Date now = new java.util.Date();
>       DataContext dc = (DataContext) company.getObjectContext();
>
>       Task task = dc.newObject(Task.class);
>       task.setCreatedBy(user);
>       task.setLastModifiedBy(user);
>       task.setCreatedWhen(now);
>       task.setTargetDate(now);
>       task.setTimeWhen(now);
>       task.setCompany(company);
>       task.setAssignedTo(user);
>       user.addToTasks(task);
>       task.setType(taskType);
>
>       try {
>           dc.commitChanges();
>       }
>       catch (CayenneRuntimeException e) {
>           e.printStackTrace();
>       }
>   }
>
>   private void deleteTask(Task task)
>   {
>       DataContext dc = (DataContext) task.getObjectContext();
>       dc.deleteObject(task);
>
>       try {
>           dc.commitChanges();
>       }
>       catch (CayenneRuntimeException e) {
>           e.printStackTrace();
>       }
>   }
>
>   private long pauseMillis = 1000;
>
>   private void pause()
>   {
>       if (pauseMillis > 0) {
>           debug("pausing...");
>           try {
>               Thread.sleep(pauseMillis);
>           }
>           catch (InterruptedException ex) {
>               ex.printStackTrace();
>           }
>       }
>   }


Mime
View raw message