Skip to content

Commit

Permalink
Merge pull request #669 from renebock/concurrency
Browse files Browse the repository at this point in the history
Concurrency
  • Loading branch information
darkv committed Aug 11, 2015
2 parents c74c556 + 64f51ab commit e1cd5c9
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOComponent;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOObjectStore;
import com.webobjects.eocontrol.EOObjectStoreCoordinator;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSForwardException;
import com.webobjects.foundation.NSMutableArray;
Expand Down Expand Up @@ -86,7 +89,9 @@ public static NSArray tasks() {
}

public abstract class DefaultImplementation implements Runnable, ERXLongResponseTask {

private volatile EOObjectStore _parentObjectStore;
private Long _taskEditingContextTimestampLag;


/** logging support */
public Logger log = Logger.getLogger(ERXUtilities.class);
Expand Down Expand Up @@ -344,5 +349,92 @@ public WOComponent nextPage() {
*/
public abstract Object performAction();

//---------------------- Copied from ERXTask -------------------------------------

/**
* See Effective Java item #71 for explanation of this threadsafe lazy
* initialization technique
*
* @return the parent, usually an {@link EOObjectStoreCoordinator} to
* partition the task's EOF intensive work form the rest of the app.
*/
protected final EOObjectStore parentObjectStore() {
EOObjectStore osc = _parentObjectStore;
if (osc == null) {
synchronized (this) {
osc = _parentObjectStore;
if (osc == null) {
_parentObjectStore = osc = ERXTaskObjectStoreCoordinatorPool.objectStoreCoordinator();
}
}
}
return osc;
}

/**
* @param parentObjectStore
* the parent, usually an {@link EOObjectStoreCoordinator} to
* partition the task's EOF intensive work from the rest of the
* app. If you are going to manually set this, you should do it
* before starting the task.
*/
public final synchronized void setParentObjectStore(EOObjectStore parentObjectStore) {
_parentObjectStore = parentObjectStore;
}

/**
* <strong>You must manually lock and unlock the editing context returned by
* this method.</strong> It is not recommended that you depend on auto
* locking in background threads.
*
* Even though this method currently returns an auto-locking EC if
* auto-locking is turned on for the app, a future update is planned that
* will return a manually locking EC from this method even if auto-locking
* is turned on for regular ECs used in normal request-response execution.
*
* @return a new EOEditingContext.
*/
protected EOEditingContext newEditingContext() {
EOEditingContext ec = ERXEC.newEditingContext(parentObjectStore());
// if this is not a nested EC, we can set the fetch time stamp
if (!(parentObjectStore() instanceof EOEditingContext)) {
ec.setFetchTimestamp(taskEditingContextTimestampLag());
}
return ec;
}

/**
* By design EOEditingContext's have a fetch timestamp (default is 1 hour)
* that effectively creates an in-memory caching system for EOs. This works
* great for users browsing through pages in the app. However, experience
* has shown that background EOF tasks are performing updates based on the
* state of other EOs, and thus we want to This is a long-running task. The
* last thing I want to do is perform a long running task with stale EOs, so
* we lazily create a fetch timestamp of the current time when we create the
* first EC and thus ensure fresh data. Secondly, we continue, by default to
* use this timestamp for the duration of the task since experience has
* shown that by doing so we can prevent unnecessary database fetching
* especially when our task is adding lots of items to a single relationship
* in batches.
*
* However if you want fresh data each time you create an EC in your task,
* feel free to set the fetch time stamp to the current time in your task
* each time you create a new EC.
*
* For R-R ec's we prefer fresh data on new pages. However for long running
* tasks, it is often best pick a single point in time, usually when the
* first ec is created as the timestamp lag. This works well when we are
* iterating and making new ec's especially if we are adding 100's of items
* to a relationship and cycling ec's
*
* @return the timestamp lag to use for new ec's created in the task thread.
*/
protected long taskEditingContextTimestampLag() {
if (_taskEditingContextTimestampLag == null) {
_taskEditingContextTimestampLag = Long.valueOf(System.currentTimeMillis());
}
return _taskEditingContextTimestampLag.longValue();
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ protected EOEditingContext newEditingContext() {
*
* @return the timestamp lag to use for new ec's created in the task thread.
*/
private long taskEditingContextTimestampLag() {
protected long taskEditingContextTimestampLag() {
if (_taskEditingContextTimestampLag == null) {
_taskEditingContextTimestampLag = Long.valueOf(System.currentTimeMillis());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOObjectStore;
import com.webobjects.eocontrol.EOObjectStoreCoordinator;
import com.webobjects.woextensions.WOLongResponsePage;

import er.extensions.appserver.ERXApplication;
import er.extensions.eof.ERXEC;

/**
* ERXWOLongResponsePage is just like WOLongResponsePage except that it
Expand All @@ -21,6 +25,9 @@ public abstract class ERXWOLongResponsePage extends WOLongResponsePage {
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
private volatile EOObjectStore _parentObjectStore;
private Long _taskEditingContextTimestampLag;


public ERXWOLongResponsePage(WOContext context) {
super(context);
Expand All @@ -44,4 +51,92 @@ public void run() {
ERXApplication._endRequest();
}
}

//---------------------- Copied from ERXTask -------------------------------------

/**
* See Effective Java item #71 for explanation of this threadsafe lazy
* initialization technique
*
* @return the parent, usually an {@link EOObjectStoreCoordinator} to
* partition the task's EOF intensive work form the rest of the app.
*/
protected final EOObjectStore parentObjectStore() {
EOObjectStore osc = _parentObjectStore;
if (osc == null) {
synchronized (this) {
osc = _parentObjectStore;
if (osc == null) {
_parentObjectStore = osc = ERXTaskObjectStoreCoordinatorPool.objectStoreCoordinator();
}
}
}
return osc;
}

/**
* @param parentObjectStore
* the parent, usually an {@link EOObjectStoreCoordinator} to
* partition the task's EOF intensive work from the rest of the
* app. If you are going to manually set this, you should do it
* before starting the task.
*/
public final synchronized void setParentObjectStore(EOObjectStore parentObjectStore) {
_parentObjectStore = parentObjectStore;
}

/**
* <strong>You must manually lock and unlock the editing context returned by
* this method.</strong> It is not recommended that you depend on auto
* locking in background threads.
*
* Even though this method currently returns an auto-locking EC if
* auto-locking is turned on for the app, a future update is planned that
* will return a manually locking EC from this method even if auto-locking
* is turned on for regular ECs used in normal request-response execution.
*
* @return a new EOEditingContext.
*/
protected EOEditingContext newEditingContext() {
EOEditingContext ec = ERXEC.newEditingContext(parentObjectStore());
// if this is not a nested EC, we can set the fetch time stamp
if (!(parentObjectStore() instanceof EOEditingContext)) {
ec.setFetchTimestamp(taskEditingContextTimestampLag());
}
return ec;
}

/**
* By design EOEditingContext's have a fetch timestamp (default is 1 hour)
* that effectively creates an in-memory caching system for EOs. This works
* great for users browsing through pages in the app. However, experience
* has shown that background EOF tasks are performing updates based on the
* state of other EOs, and thus we want to This is a long-running task. The
* last thing I want to do is perform a long running task with stale EOs, so
* we lazily create a fetch timestamp of the current time when we create the
* first EC and thus ensure fresh data. Secondly, we continue, by default to
* use this timestamp for the duration of the task since experience has
* shown that by doing so we can prevent unnecessary database fetching
* especially when our task is adding lots of items to a single relationship
* in batches.
*
* However if you want fresh data each time you create an EC in your task,
* feel free to set the fetch time stamp to the current time in your task
* each time you create a new EC.
*
* For R-R ec's we prefer fresh data on new pages. However for long running
* tasks, it is often best pick a single point in time, usually when the
* first ec is created as the timestamp lag. This works well when we are
* iterating and making new ec's especially if we are adding 100's of items
* to a relationship and cycling ec's
*
* @return the timestamp lag to use for new ec's created in the task thread.
*/
protected long taskEditingContextTimestampLag() {
if (_taskEditingContextTimestampLag == null) {
_taskEditingContextTimestampLag = Long.valueOf(System.currentTimeMillis());
}
return _taskEditingContextTimestampLag.longValue();
}

}

0 comments on commit e1cd5c9

Please sign in to comment.