[Swift-commit] Cog update
swift at ci.uchicago.edu
swift at ci.uchicago.edu
Sat Jan 28 20:50:18 CST 2012
------------------------------------------------------------------------
r3355 | hategan | 2012-01-28 20:48:37 -0600 (Sat, 28 Jan 2012) | 1 line
merged 0.93 to trunk
------------------------------------------------------------------------
Index: lib/log4j.LICENSE
===================================================================
--- lib/log4j.LICENSE (revision 0)
+++ lib/log4j.LICENSE (revision 3355)
@@ -0,0 +1,49 @@
+/*
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
+ *
+ * Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "log4j" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * apache at apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This software consists of voluntary contributions made by many individuals
+ * on behalf of the Apache Software Foundation. For more information on the
+ * Apache Software Foundation, please see <http://www.apache.org/>.
+ *
+ */
+
Index: lib/log4j-1.2.8.LICENSE
===================================================================
--- lib/log4j-1.2.8.LICENSE (revision 3354)
+++ lib/log4j-1.2.8.LICENSE (working copy)
@@ -1,49 +0,0 @@
-/*
- * ============================================================================
- * The Apache Software License, Version 1.1
- * ============================================================================
- *
- * Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modifica-
- * tion, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. The end-user documentation included with the redistribution, if any, must
- * include the following acknowledgment: "This product includes software
- * developed by the Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself, if
- * and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "log4j" and "Apache Software Foundation" must not be used to
- * endorse or promote products derived from this software without prior
- * written permission. For written permission, please contact
- * apache at apache.org.
- *
- * 5. Products derived from this software may not be called "Apache", nor may
- * "Apache" appear in their name, without prior written permission of the
- * Apache Software Foundation.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
- * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * This software consists of voluntary contributions made by many individuals
- * on behalf of the Apache Software Foundation. For more information on the
- * Apache Software Foundation, please see <http://www.apache.org/>.
- *
- */
-
Index: lib/backport-util-concurrent.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: lib/log4j-1.2.8.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: modules/provider-localscheduler/.classpath
===================================================================
--- modules/provider-localscheduler/.classpath (revision 3354)
+++ modules/provider-localscheduler/.classpath (working copy)
@@ -10,6 +10,7 @@
</accessrules>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/util"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-localscheduler/src/org/globus/cog/abstraction/impl/scheduler/pbs/PBSExecutor.java
===================================================================
--- modules/provider-localscheduler/src/org/globus/cog/abstraction/impl/scheduler/pbs/PBSExecutor.java (revision 3354)
+++ modules/provider-localscheduler/src/org/globus/cog/abstraction/impl/scheduler/pbs/PBSExecutor.java (working copy)
@@ -31,6 +31,7 @@
public class PBSExecutor extends AbstractExecutor {
public static final Logger logger = Logger.getLogger(PBSExecutor.class);
+
/**
Number of program invocations
*/
@@ -60,7 +61,6 @@
/**
The job name is limited to 15 characters:
http://doesciencegrid.org/public/pbs/qsub.html
- This limit is enforced on Cray machines
*/
protected void validate(Task task) {
String name = task.getName();
@@ -76,10 +76,7 @@
}
}
else if (name.length() > 15) {
- String shorter = name.substring(0, 15);
- logger.debug("PBS name: for: " + name +
- " is: " + shorter);
- task.setName(shorter);
+ task.setName(name.substring(0, 15));
}
}
@@ -327,6 +324,7 @@
writer.write("#CoG on date: " + new Date() + "\n\n");
}
+
private String makeList(Collection<String> names) {
StringBuilder sb = new StringBuilder();
Iterator<String> i = names.iterator();
Index: modules/provider-localscheduler/src/org/globus/cog/abstraction/impl/scheduler/sge/SGEExecutor.java
===================================================================
--- modules/provider-localscheduler/src/org/globus/cog/abstraction/impl/scheduler/sge/SGEExecutor.java (revision 3354)
+++ modules/provider-localscheduler/src/org/globus/cog/abstraction/impl/scheduler/sge/SGEExecutor.java (working copy)
@@ -185,7 +185,8 @@
/**
* @see AbstractExecutor#start()
*/
- public void start() throws AuthorizationException, IOException, ProcessException {
+ public void start() throws AuthorizationException,
+ IOException, ProcessException {
try {
Thread.sleep(Integer.valueOf(getSGEProperties().getSubmissionDelay()));
}
Index: modules/provider-localscheduler/etc/provider-sge.properties
===================================================================
--- modules/provider-localscheduler/etc/provider-sge.properties (revision 3354)
+++ modules/provider-localscheduler/etc/provider-sge.properties (working copy)
@@ -13,14 +13,13 @@
#
# The path to qstat. The default assumes that qstat is in PATH
#
-qstat=qstat
+qstat=qstat -xml
#
# The path to qdel. The default assumes that qdel is in PATH
#
qdel=qdel
-
#
# If the jobType attribute is specified, then the SGE provider
# will look for a property named "wrapper.<jobType>" and prepend
@@ -36,6 +35,10 @@
# a default parallel environment. It can be overriden using
# the "pe" job attribute
#
-
parallel.environment=1way
+# Some systems (notably Ranger) may not adequately handle
+# a rapid submission of jobs. Use this setting to introduce
+# a delay. The value is in milliseconds (1000ms = 1s)
+#
+submission.delay=1000
Index: modules/provider-local/.classpath
===================================================================
--- modules/provider-local/.classpath (revision 3354)
+++ modules/provider-local/.classpath (working copy)
@@ -10,7 +10,6 @@
</accessrules>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/backport-util-concurrent"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-local/.project
===================================================================
--- modules/provider-local/.project (revision 3354)
+++ modules/provider-local/.project (working copy)
@@ -7,6 +7,11 @@
<project>jglobus</project>
</projects>
<buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
Index: modules/provider-local/src/org/globus/cog/abstraction/impl/file/local/FileResourceImpl.java
===================================================================
--- modules/provider-local/src/org/globus/cog/abstraction/impl/file/local/FileResourceImpl.java (revision 3354)
+++ modules/provider-local/src/org/globus/cog/abstraction/impl/file/local/FileResourceImpl.java (working copy)
@@ -230,6 +230,9 @@
if (dst.getCanonicalPath().equals(src.getCanonicalPath())) {
return;
}
+
+ checkParameters(remote, local, src, dst);
+
FileInputStream remoteStream = null;
FileOutputStream localStream = null;
try {
@@ -239,9 +242,16 @@
long crt = 0;
long total = Math.min(src.length(), remote.getLength());
+ if (logger.isDebugEnabled()) {
+ logger.debug(src + ": srclen = " + src.length()
+ + ", len = " + remote.getLength() + ", total = " + total);
+ }
byte[] buf = new byte[16384];
do {
- int read = remoteStream.read(buf, 0, Math.min(buf.length, (int) (total - crt)));
+ if (logger.isDebugEnabled()) {
+ logger.debug(src + ": crt = " + crt + ", total - crt = " + (total - crt));
+ }
+ int read = remoteStream.read(buf, 0, (int) Math.min(buf.length, total - crt));
localStream.write(buf, 0, read);
crt += read;
if (progressMonitor != null) {
@@ -263,6 +273,14 @@
}
}
+ private void checkParameters(FileFragment srcf, FileFragment dstf, File src, File dst) throws FileResourceException {
+ long srcLen = src.length();
+ if (srcf.getOffset() > srcLen) {
+ throw new FileResourceException("Requested file offset ("
+ + srcf.getOffset() + ") is larger than the file size (" + srcLen + ")");
+ }
+ }
+
public void putFile(FileFragment local, FileFragment remote,
ProgressMonitor progressMonitor) throws FileResourceException {
getFile(local, remote, progressMonitor);
@@ -439,12 +457,10 @@
return true;
}
- @Override
public boolean supportsPartialTransfers() {
return true;
}
- @Override
public boolean supportsThirdPartyTransfers() {
return false;
}
Index: modules/provider-local/src/org/globus/cog/abstraction/impl/execution/local/JobSubmissionTaskHandler.java
===================================================================
--- modules/provider-local/src/org/globus/cog/abstraction/impl/execution/local/JobSubmissionTaskHandler.java (revision 3354)
+++ modules/provider-local/src/org/globus/cog/abstraction/impl/execution/local/JobSubmissionTaskHandler.java (working copy)
@@ -219,7 +219,7 @@
int exitCode = p.waitFor();
if (logger.isDebugEnabled()) {
- logger.debug("Exit code was " + exitCode);
+ logger.debug("Application " + spec.getExecutable() + " failed with an exit code of " + exitCode);
}
/*
@@ -343,6 +343,7 @@
String srcScheme = defaultToLocal(suri.getScheme());
String dstScheme = defaultToLocal(duri.getScheme());
+
Service ss = new ServiceImpl(srcScheme, getServiceContact(suri), null);
Service ds = new ServiceImpl(dstScheme, getServiceContact(duri), null);
@@ -607,7 +608,7 @@
int avail = sp.is.available();
if (avail > 0) {
any = true;
- int len = sp.is.read(buf);
+ int len = sp.is.read(buf, 0, Math.min(avail, BUFFER_SIZE));
sp.os.write(buf, 0, len);
}
}
Index: modules/provider-gt2/.classpath
===================================================================
--- modules/provider-gt2/.classpath (revision 3354)
+++ modules/provider-gt2/.classpath (working copy)
@@ -11,7 +11,6 @@
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/util"/>
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/jglobus"/>
- <classpathentry exported="true" kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j-1.2.8"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-gt2/src/org/globus/cog/abstraction/impl/file/gridftp/old/FileResourceImpl.java
===================================================================
--- modules/provider-gt2/src/org/globus/cog/abstraction/impl/file/gridftp/old/FileResourceImpl.java (revision 3354)
+++ modules/provider-gt2/src/org/globus/cog/abstraction/impl/file/gridftp/old/FileResourceImpl.java (working copy)
@@ -755,12 +755,10 @@
return true;
}
- @Override
public boolean supportsPartialTransfers() {
return true;
}
- @Override
public boolean supportsThirdPartyTransfers() {
return true;
}
@@ -849,4 +847,4 @@
}
return NF.format(dv) + " " + U[index];
}
-}
\ No newline at end of file
+}
Index: modules/provider-gt2/src/org/globus/cog/abstraction/impl/file/ftp/FileResourceImpl.java
===================================================================
--- modules/provider-gt2/src/org/globus/cog/abstraction/impl/file/ftp/FileResourceImpl.java (revision 3354)
+++ modules/provider-gt2/src/org/globus/cog/abstraction/impl/file/ftp/FileResourceImpl.java (working copy)
@@ -563,12 +563,10 @@
return true;
}
- @Override
public boolean supportsPartialTransfers() {
return false;
}
- @Override
public boolean supportsThirdPartyTransfers() {
return false;
}
Index: modules/provider-gt4_0_0/.classpath
===================================================================
--- modules/provider-gt4_0_0/.classpath (revision 3354)
+++ modules/provider-gt4_0_0/.classpath (working copy)
@@ -46,6 +46,6 @@
<classpathentry exported="true" kind="lib" path="lib/cog-provider-clref-gt4_0_0.jar"/>
<classpathentry exported="true" kind="lib" path="lib/concurrent.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-ssh/.classpath
===================================================================
--- modules/provider-ssh/.classpath (revision 3354)
+++ modules/provider-ssh/.classpath (working copy)
@@ -11,8 +11,7 @@
</classpathentry>
<classpathentry kind="lib" path="lib/j2ssh-common-0.2.2.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j-1.2.8"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
<classpathentry kind="lib" path="lib/j2ssh-core-0.2.2-patch-b.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-ssh/src/org/globus/cog/abstraction/impl/ssh/file/FileResourceImpl.java
===================================================================
--- modules/provider-ssh/src/org/globus/cog/abstraction/impl/ssh/file/FileResourceImpl.java (revision 3354)
+++ modules/provider-ssh/src/org/globus/cog/abstraction/impl/ssh/file/FileResourceImpl.java (working copy)
@@ -386,12 +386,10 @@
throw new TaskSubmissionException("Not implemented");
}
- @Override
public boolean supportsPartialTransfers() {
return false;
}
- @Override
public boolean supportsThirdPartyTransfers() {
return false;
}
Index: modules/provider-coaster/.classpath
===================================================================
--- modules/provider-coaster/.classpath (revision 3354)
+++ modules/provider-coaster/.classpath (working copy)
@@ -11,9 +11,8 @@
<classpathentry combineaccessrules="false" kind="src" path="/karajan"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry exported="true" kind="con" path="org.eclipse.jdt.USER_LIBRARY/backport-util-concurrent"/>
- <classpathentry kind="lib" path="/util/lib/backport-util-concurrent.jar"/>
<classpathentry kind="src" path="/abstraction-provider-local"/>
<classpathentry kind="src" path="/util"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/CoasterPersistentService.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/CoasterPersistentService.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/CoasterPersistentService.java (working copy)
@@ -69,7 +69,7 @@
ap.addFlag("local", "Binds the service to the loopback interface");
ap.addFlag("passive",
"Initialize the passive worker service and " +
- "set the passive worker manager to be the default");
+ "set the passive worker manager to be the default (otherwise the block allocator will be used)");
ap.addFlag("help", "Displays usage information");
ap.addAlias("help", "h");
try {
@@ -145,7 +145,12 @@
writePorts(s, portFile, localPortFile);
s.setIgnoreIdleTime(true);
- s.setDefaultQP("passive");
+ if (ap.isPresent("passive")) {
+ s.setDefaultQP("passive");
+ }
+ else {
+ s.setDefaultQP("block");
+ }
s.start();
System.out.println("Started coaster service: " + s);
s.waitFor();
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/local/LocalService.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/local/LocalService.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/local/LocalService.java (working copy)
@@ -19,6 +19,7 @@
import org.apache.log4j.Logger;
import org.globus.cog.abstraction.coaster.service.Registering;
import org.globus.cog.abstraction.impl.common.AbstractionFactory;
+import org.globus.cog.abstraction.impl.common.execution.JobException;
import org.globus.cog.abstraction.impl.common.task.TaskSubmissionException;
import org.globus.cog.abstraction.interfaces.Service;
import org.globus.cog.abstraction.interfaces.Status;
@@ -117,7 +118,7 @@
throw new TaskSubmissionException("Task ended before registration was received"
+ (s.getMessage() == null ? ". " : ": " + s.getMessage())
+ out("STDOUT", t.getStdOutput()) + out("STDERR", t.getStdError()),
- s.getException());
+ s.getException() instanceof JobException ? null : s.getException());
}
}
return services.get(id);
@@ -126,7 +127,7 @@
private String out(String name, String value) {
if (value != null) {
- return "\n" + name + ": " + value;
+ return "\n" + value;
}
else {
return "";
@@ -146,7 +147,7 @@
}
public String registrationReceived(String id, String url, KarajanChannel channel,
- Map<String, String> options) {
+ Map<String, String> options) {
if (logger.isDebugEnabled()) {
logger.debug("Received registration from service " + id + ": " + url);
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/TCPBufferManager.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/TCPBufferManager.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/TCPBufferManager.java (working copy)
@@ -79,7 +79,9 @@
int crt = crtSocketBuffSz / BUFFER_SIZE_GRANULARITY;
int old = crt;
- logger.debug("crt: " + crt + ", #sockets: " + sockets.size() + ", min: " + min + ", max: " + max);
+ if (logger.isDebugEnabled()) {
+ logger.debug("crt: " + crt + ", #sockets: " + sockets.size() + ", min: " + min + ", max: " + max);
+ }
if (sockets.size() == 0) {
logger.debug("No sockets");
return;
@@ -91,7 +93,9 @@
if (crtSocketBuffSz < MIN_BUFFER_SIZE) {
crtSocketBuffSz = MIN_BUFFER_SIZE;
}
- logger.debug("Adjusting buffer size to " + crtSocketBuffSz);
+ if (logger.isInfoEnabled()) {
+ logger.info("Adjusting buffer size to " + crtSocketBuffSz);
+ }
updateBufferSizes();
}
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/LocalTCPService.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/LocalTCPService.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/LocalTCPService.java (working copy)
@@ -51,7 +51,7 @@
}
public String registrationReceived(String blockid, String url,
- KarajanChannel channel, Map<String, String> options) throws ChannelException {
+ KarajanChannel channel) throws ChannelException {
if (logger.isInfoEnabled()) {
logger.info("Received registration: blockid = " +
blockid + ", url = " + url);
@@ -61,7 +61,7 @@
String wid = registrationManager.nextId(blockid);
cc.getChannelID().setRemoteID(wid);
ChannelManager.getManager().registerChannel(cc.getChannelID(), channel);
- registrationManager.registrationReceived(blockid, wid, url, cc, options);
+ registrationManager.registrationReceived(blockid, wid, url, cc);
return wid;
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/Registering.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/Registering.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/Registering.java (working copy)
@@ -15,8 +15,7 @@
import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
public interface Registering {
- String registrationReceived(String id, String url, KarajanChannel channel,
- Map<String, String> options) throws ChannelException;
+ String registrationReceived(String id, String url, KarajanChannel channel, Map<String, String> options) throws ChannelException;
void unregister(String id);
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/ServiceConfigurationHandler.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/ServiceConfigurationHandler.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/ServiceConfigurationHandler.java (working copy)
@@ -26,8 +26,6 @@
Settings settings =
((CoasterService) getChannel().getChannelContext().getService()).getJobQueue().getSettings();
- logger.debug(settings);
-
try {
List<byte[]> l = getInDataChunks();
if (l != null) {
@@ -37,6 +35,7 @@
settings.set(p[0], p[1]);
}
}
+ logger.debug(settings);
sendReply("OK");
}
catch (Exception e) {
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/TimeInterval.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/TimeInterval.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/TimeInterval.java (working copy)
@@ -72,7 +72,7 @@
return ms;
}
- public static TimeInterval fromSeconds(int seconds) {
+ public static TimeInterval fromSeconds(long seconds) {
return new TimeInterval(seconds * 1000);
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/BlockTask.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/BlockTask.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/BlockTask.java (working copy)
@@ -41,7 +41,11 @@
setSpecification(spec);
setName("B" + block.getId());
setAttribute(spec, "maxwalltime", WallTime.format((int) block.getWalltime().getSeconds()));
+ setAttribute(spec, "jobsPerNode", settings.getJobsPerNode());
+ setAttribute(spec, "coresPerNode", settings.getCoresPerNode());
+
int count = block.getWorkerCount() / settings.getJobsPerNode();
+
if (count > 1) {
setAttribute(spec, "jobType", "multiple");
}
@@ -51,8 +55,7 @@
for (String name : settings.getAttributeNames()) {
setAttribute(spec, name, settings.getAttribute(name));
}
- setAttribute(spec, "providerAttributes", settings.getProviderAttributes());
- // logger.trace("providerAttributes: " + settings.getProviderAttributes());
+
String libraryPath = settings.getLdLibraryPath();
if (libraryPath != null)
spec.addEnvironmentVariable("LD_LIBRARY_PATH",
@@ -91,6 +94,7 @@
js.setExecutable("/usr/bin/perl");
js.addArgument(script);
}
+
// Cobalt on Intrepid, if no directory is specified, assumes $CWD for the
// job directory.
// If $CWD happens to be /scratch/something it has a filter in place
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/JobSet.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/JobSet.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/JobSet.java (working copy)
@@ -10,9 +10,10 @@
package org.globus.cog.abstraction.coaster.service.job.manager;
import java.util.HashSet;
+import java.util.Iterator;
import java.util.Set;
-public class JobSet {
+public class JobSet implements Iterable<Job> {
private Set<Job> jobs;
private Metric metric;
@@ -56,4 +57,8 @@
return sum;
}
+
+ public Iterator<Job> iterator() {
+ return jobs.iterator();
+ }
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/BlockQueueProcessor.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/BlockQueueProcessor.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/BlockQueueProcessor.java (working copy)
@@ -21,6 +21,7 @@
import org.globus.cog.abstraction.coaster.service.CoasterService;
import org.globus.cog.abstraction.coaster.service.RegistrationManager;
import org.globus.cog.abstraction.impl.common.AbstractionFactory;
+import org.globus.cog.abstraction.impl.common.execution.WallTime;
import org.globus.cog.abstraction.interfaces.ExecutionService;
import org.globus.cog.abstraction.interfaces.Task;
import org.globus.cog.karajan.workflow.service.channels.ChannelContext;
@@ -160,18 +161,32 @@
public void enqueue1(Task t) {
synchronized (incoming) {
Job j = new Job(t);
- if (logger.isDebugEnabled()) {
- logger.debug("Got job with walltime = " + j.getMaxWallTime());
+ if (checkJob(j)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Got job with walltime = " + j.getMaxWallTime());
+ }
+ if (planning) {
+ incoming.add(j);
+ }
+ else {
+ queue(j);
+ }
}
- if (planning) {
- incoming.add(j);
- }
- else {
- queue(j);
- }
}
}
+ private boolean checkJob(Job job) {
+ if (job.getMaxWallTime().getSeconds() > settings.getMaxtime() - settings.getReserve().getSeconds()) {
+ job.fail("Job walltime > maxTime - reserve (" +
+ WallTime.format("hms", job.getMaxWallTime().getSeconds()) + " > " +
+ WallTime.format("hms", settings.getMaxtime() - settings.getReserve().getSeconds()) + ")", null);
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
public void enqueue(List<Job> jobs) {
synchronized (incoming) {
incoming.addAll(jobs);
@@ -179,8 +194,8 @@
}
private void queue(Job job) {
- synchronized (queued) {
- queued.add(job);
+ synchronized (queued) {
+ queued.add(job);
queued.notify();
}
}
@@ -245,7 +260,7 @@
}
private Set<Job> queueToExistingBlocks() {
- double runningSize = running.getSizeLeft();
+ double runningSize = getRunningSizeLeft();
Set<Job> remove = new HashSet<Job>();
for (Job j : holding) {
if (allocsize - queued.getJSize() - runningSize > metric.getSize(j) && fits(j)) {
@@ -261,7 +276,7 @@
private void requeueNonFitting() {
int count = 0;
- double runningSize = running.getSizeLeft();
+ double runningSize = getRunningSizeLeft();
logger.debug("allocsize = " + allocsize +
", queuedsize = " + queued.getJSize() +
", running = " + runningSize +
@@ -270,8 +285,13 @@
Job j = queued.removeOne(TimeInterval.FOREVER,
Integer.MAX_VALUE);
if (j == null) {
- CoasterService.error(19, "queued size > 0 but no job dequeued. Queued: " + queued,
- new Throwable());
+ if (queued.getJSize() > 0) {
+ CoasterService.error(19, "queuedsize > 0 but no job dequeued. Queued: " + queued,
+ new Throwable());
+ }
+ else if (allocsize - getRunningSizeLeft() < 0) {
+ warnAboutWalltimes(running);
+ }
}
holding.add(j);
count++;
@@ -280,7 +300,28 @@
logger.info("Requeued " + count + " non-fitting jobs");
}
}
+
+ private void warnAboutWalltimes(Iterable<Job> set) {
+ synchronized(set) {
+ for (Job r : set) {
+ if (r.getMaxWallTime().isLessThan(Time.now().subtract(r.getStartTime()))) {
+ Task t = r.getTask();
+ if (t.getAttribute("#warnedAboutWalltime") == null) {
+ logger.warn("The following job exceeded its walltime: " +
+ t.getSpecification());
+ t.setAttribute("#warnedAboutWalltime", Boolean.TRUE);
+ }
+ }
+ }
+ }
+ }
+ private double getRunningSizeLeft() {
+ synchronized(running) {
+ return running.getSizeLeft();
+ }
+ }
+
private void computeSums() {
sums = new ArrayList<Integer>(holding.size());
sums.add(0);
@@ -614,13 +655,17 @@
public Job request(TimeInterval ti, int cpus) {
Job job = queued.removeOne(ti, cpus);
if (job != null) {
- running.add(job);
+ synchronized(running) {
+ running.add(job);
+ }
}
return job;
}
public void jobTerminated(Job job) {
- running.remove(job);
+ synchronized(running) {
+ running.remove(job);
+ }
}
/**
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Settings.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Settings.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Settings.java (working copy)
@@ -50,13 +50,19 @@
"workerLoggingDirectory",
"ldLibraryPath", "workerCopies",
"directory", "useHashBang",
- "providerAttributes", "parallelism" };
+ "parallelism",
+ "coresPerNode"};
/**
* The maximum number of blocks that can be active at one time
*/
private int slots = 20;
private int jobsPerNode = 1;
+
+ /**
+ * TODO: clarify what this does
+ */
+ private String coresPerNode = "1";
/**
* How many nodes to allocate at once
@@ -113,7 +119,7 @@
private SecurityContext securityContext;
private boolean remoteMonitorEnabled;
-
+
/**
* Adjusts the metric used for block sizes.
*
@@ -155,10 +161,13 @@
private String useHashBang = null;
- private String providerAttributes = null;
-
private final Map<String, String> attributes;
+ /**
+ * A pass-through setting for SGE, parallel environment
+ */
+ private String pe;
+
public Settings() {
hook = new Hook();
callbackURIs = new TreeSet<URI>();
@@ -304,14 +313,6 @@
return workerLoggingDirectory;
}
- public String getProviderAttributes() {
- return providerAttributes;
- }
-
- public void setProviderAttributes(String options) {
- providerAttributes = options;
- }
-
/**
* The following values are considered valid:
* <dl>
@@ -466,6 +467,13 @@
this.parallelism = parallelism;
}
+ public String getCoresPerNode() {
+ return coresPerNode;
+ }
+
+ public void setCoresPerNode(String coresPerNode) {
+ this.coresPerNode=coresPerNode;
+ }
public String getHookClass() {
return hookClass;
}
@@ -519,7 +527,7 @@
public void setUseHashBang(String uhb) {
this.useHashBang = uhb;
}
-
+
public void setAttribute(String name, String value) {
attributes.put(name, value);
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Cpu.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Cpu.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Cpu.java (working copy)
@@ -20,9 +20,12 @@
import org.globus.cog.abstraction.interfaces.Status;
import org.globus.cog.abstraction.interfaces.StatusListener;
import org.globus.cog.abstraction.interfaces.Task;
+import org.globus.cog.karajan.workflow.service.channels.ChannelListener;
+import org.globus.cog.karajan.workflow.service.channels.ChannelManager;
import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
import org.globus.cog.karajan.workflow.service.commands.Command;
import org.globus.cog.karajan.workflow.service.commands.Command.Callback;
+import org.globus.cog.karajan.workflow.service.commands.HeartBeatCommand;
public class Cpu implements Comparable<Cpu>, Callback, StatusListener {
public static final Logger logger = Logger.getLogger(Cpu.class);
@@ -264,10 +267,12 @@
}
public void shutdown() {
- if (shutdown) {
- return;
- }
- shutdown = true;
+ synchronized(this) {
+ if (shutdown) {
+ return;
+ }
+ shutdown = true;
+ }
Block block = node.getBlock();
done.clear();
if (running != null) {
Index: modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Block.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Block.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/coaster/service/job/manager/Block.java (working copy)
@@ -194,7 +194,7 @@
public void shutdownIfEmpty(Cpu cpu) {
synchronized (scpus) {
if (scpus.isEmpty()) {
- if (logger.isInfoEnabled()) {
+ if (logger.isInfoEnabled() && !shutdown) {
logger.info(this + ": all cpus are clear");
}
shutdown(false);
@@ -269,9 +269,16 @@
}
if (!failed) {
if (count < workers || now) {
+ if (logger.isInfoEnabled()) {
+ logger.info("Adding short shutdown watchdog: count = " +
+ count + ", workers = " + workers + ", now = " + now);
+ }
addForcedShutdownWatchdog(100);
}
else {
+ if (logger.isInfoEnabled()) {
+ logger.info("Adding normal shutdown watchdog");
+ }
addForcedShutdownWatchdog(SHUTDOWN_WATCHDOG_DELAY);
}
}
@@ -304,18 +311,16 @@
}
public void forceShutdown() {
- if (task != null) {
- try {
- getSubmitter().cancel(this);
- }
- catch (Exception e) {
- if (failed)
- logger.debug("Failed to shut down block: " +
- this + " " + e.getMessage());
- else
+ synchronized(cpus) {
+ if (task != null) {
+ try {
+ getSubmitter().cancel(this);
+ }
+ catch (Exception e) {
logger.warn("Failed to shut down block: " + this, e);
+ }
+ bqp.blockTaskFinished(this);
}
- bqp.blockTaskFinished(this);
}
}
@@ -375,7 +380,7 @@
}
}
}
-
+
private int seq;
public String nextId() {
@@ -414,9 +419,8 @@
}
bqp.blockTaskFinished(this);
running = false;
+ task = null;
}
- logger.info(id + " stdout: " + prettifyOut(task.getStdOutput()));
- logger.info(id + " stderr: " + prettifyOut(task.getStdError()));
}
else if (s.getStatusCode() == Status.ACTIVE) {
starttime = Time.now();
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/PutFileHandler.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/PutFileHandler.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/PutFileHandler.java (working copy)
@@ -10,22 +10,30 @@
package org.globus.cog.abstraction.impl.file.coaster.handlers;
import java.io.IOException;
+import java.util.Arrays;
import org.apache.log4j.Logger;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.ThrottleManager;
import org.globus.cog.abstraction.impl.file.coaster.handlers.providers.IOHandle;
import org.globus.cog.abstraction.impl.file.coaster.handlers.providers.IOProvider;
import org.globus.cog.abstraction.impl.file.coaster.handlers.providers.IOProviderFactory;
import org.globus.cog.abstraction.impl.file.coaster.handlers.providers.IOWriter;
import org.globus.cog.abstraction.impl.file.coaster.handlers.providers.WriteIOCallback;
import org.globus.cog.karajan.workflow.service.ProtocolException;
+import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
public class PutFileHandler extends CoasterFileRequestHandler implements WriteIOCallback {
public static final Logger logger = Logger.getLogger(PutFileHandler.class);
+
+ public static final byte[] STOP = "STOP".getBytes();
+ public static final byte[] CONTINUE = "CONTINUE".getBytes();
private long len = -1;
private String src, dst;
private IOProvider provider;
private IOWriter writer;
+ private boolean done, suspended;
public void requestComplete() throws ProtocolException {
if (writer != null && provider.isDirect()) {
@@ -39,6 +47,10 @@
}
protected void addInData(boolean fin, boolean err, byte[] data) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " got data, fin = " + fin +
+ ", err = " + err + ", sz = " + data.length);
+ }
try {
if (err) {
super.addInData(fin, err, data);
@@ -46,22 +58,25 @@
else if (len == -1) {
len = unpackLong(data);
if (logger.isDebugEnabled()) {
- logger.debug(dst + " Size: " + len);
+ logger.debug(this + " " + dst + " Size: " + len);
}
}
else if (src == null) {
src = new String(data);
if (logger.isInfoEnabled()) {
- logger.info("Source: " + src);
+ logger.info(this + " source: " + src);
}
}
else if (dst == null) {
dst = new String(data);
if (logger.isInfoEnabled()) {
- logger.info("Destination: " + dst);
+ logger.info(this + " destination: " + dst);
}
provider = IOProviderFactory.getDefault().instance(getProtocol(dst));
writer = provider.push(src, dst, this);
+ if (!provider.isDirect()) {
+ writer.setUpThrottling();
+ }
writer.setLength(len);
}
else {
@@ -89,9 +104,49 @@
}
}
}
+
+ public void suspend() {
+ synchronized(this) {
+ if (done) {
+ return;
+ }
+ }
+ int tag = getId();
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " suspending");
+ }
+ suspended = true;
+ getChannel().sendTaggedReply(tag, STOP, KarajanChannel.SIGNAL_FLAG);
+ writer.suspend();
+ }
+
+ public void resume() {
+ synchronized(this) {
+ if (done) {
+ return;
+ }
+ setLastTime(System.currentTimeMillis());
+ suspended = false;
+ }
+ int tag = getId();
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " resuming");
+ }
+ getChannel().sendTaggedReply(tag, CONTINUE, KarajanChannel.SIGNAL_FLAG);
+ writer.resume();
+ }
public void done(IOHandle op) {
+ synchronized(this) {
+ done = true;
+ }
+ if (!provider.isDirect()) {
+ writer.cancelThrottling();
+ }
try {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " Transfer done");
+ }
sendReply("OK");
}
catch (ProtocolException e) {
@@ -101,12 +156,19 @@
public void error(IOHandle op, Exception e) {
try {
+ logger.warn("Failed to write file data", e);
sendError("Failed to write file data: " + e.getMessage());
}
catch (ProtocolException ee) {
logger.warn("Failed to send reply", ee);
}
}
+
+ public void info(String s) {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " -> " + s);
+ }
+ }
public void sendError(String error, Throwable e) throws ProtocolException {
if (provider != null && writer != null) {
@@ -130,6 +192,33 @@
logger.info("Failed to close output stream", e);
}
}
+ ThrottleManager.getDefault(Direction.OUT).unregister(this);
super.errorReceived(msg, t);
}
+
+ @Override
+ public void handleSignal(byte[] data) {
+ if (Arrays.equals(data, STOP)) {
+ suspended = true;
+ }
+ else if (Arrays.equals(data, CONTINUE)) {
+ synchronized(this) {
+ setLastTime(System.currentTimeMillis());
+ suspended = false;
+ }
+ }
+ else {
+ logger.warn("Unhandled signal: " + String.valueOf(data));
+ }
+ }
+
+ @Override
+ public synchronized long getLastTime() {
+ if (suspended) {
+ return Long.MAX_VALUE;
+ }
+ else {
+ return super.getLastTime();
+ }
+ }
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/GetFileHandler.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/GetFileHandler.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/GetFileHandler.java (working copy)
@@ -24,6 +24,8 @@
public class GetFileHandler extends CoasterFileRequestHandler implements SendCallback, ReadIOCallback {
public static final Logger logger = Logger.getLogger(GetFileHandler.class);
+
+ public static final String QUEUED = "QUEUED";
// private long size;
// private Exception ex;
@@ -34,6 +36,9 @@
public void requestComplete() throws ProtocolException {
String src = getInDataAsString(0);
try {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " request complete");
+ }
provider = IOProviderFactory.getDefault().instance(getProtocol(src));
sendReply();
}
@@ -64,6 +69,10 @@
}
public void dataSent() {
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " data sent");
+ }
+ setLastTime(System.currentTimeMillis());
reader.dataSent();
}
@@ -71,22 +80,48 @@
if (!lengthSent) {
throw new RuntimeException("No length provided");
}
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " sending " + data.limit());
+ }
getChannel().sendTaggedReply(getId(), data, last, false, this);
}
+ public void queued() {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " sending queued signal");
+ }
+ getChannel().sendTaggedReply(getId(), QUEUED.getBytes(), KarajanChannel.SIGNAL_FLAG, null);
+ }
+
+ public void info(String msg) {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " -> " + msg);
+ }
+ }
+
public void done(IOHandle op) {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " read done");
+ }
if (!provider.isDirect()) {
- getChannel().sendTaggedReply(getId(), "OK".getBytes(), true, false, null);
+ getChannel().sendTaggedReply(getId(), "OK".getBytes(), true, false);
reader.close();
}
}
public void error(IOHandle op, Exception e) {
- getChannel().sendTaggedReply(getId(), e.getMessage().getBytes(), true, true);
+ getChannel().sendTaggedReply(getId(), e.getMessage() != null ? e.getMessage().getBytes() : e.toString().getBytes(),
+ KarajanChannel.FINAL_FLAG + KarajanChannel.ERROR_FLAG);
}
public void length(long len) {
if (provider.isDirect()) {
+ if (lengthSent) {
+ logger.warn("length() called twice", new Throwable("xz0001"));
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " sending length: " + len + ", " + System.identityHashCode(this));
+ }
lengthSent = true;
getChannel().sendTaggedReply(getId(), pack(len), len == 0, false);
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/WriteIOCallback.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/WriteIOCallback.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/WriteIOCallback.java (working copy)
@@ -11,4 +11,10 @@
public interface WriteIOCallback extends IOCallback {
+ void info(String valueOf);
+
+ void suspend();
+
+ void resume();
+
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ReadIOCallback.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ReadIOCallback.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ReadIOCallback.java (working copy)
@@ -15,4 +15,8 @@
void length(long len);
void data(IOHandle handle, ByteBuffer data, boolean last);
+
+ void info(String msg);
+
+ void queued();
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/CoGResourceIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/CoGResourceIOProvider.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/CoGResourceIOProvider.java (working copy)
@@ -18,8 +18,10 @@
import org.apache.log4j.Logger;
import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBufferCallback;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.ThrottleManager;
import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBufferCallback;
import org.globus.cog.abstraction.impl.file.coaster.handlers.CoasterFileRequestHandler;
@@ -44,6 +46,8 @@
}
private static class Writer implements IOWriter, WriteBufferCallback, Abortable {
+ private static final Direction BUFDIR = Direction.OUT;
+
private File f;
private long len, crt;
private WriteIOCallback cb;
@@ -71,7 +75,7 @@
cb.done(this);
}
else {
- buf = Buffers.newWriteBuffer(new FileOutputStream(f).getChannel(), this);
+ buf = Buffers.newWriteBuffer(Buffers.getBuffers(BUFDIR), new FileOutputStream(f).getChannel(), this);
}
}
@@ -103,6 +107,28 @@
buf.close();
f.delete();
}
+
+ /**
+ * Used to notify upstream handler that the transfer
+ * has been suspended and that what otherwise would be
+ * timeouts are benign
+ */
+ public void suspend() {
+ }
+
+ /**
+ * The opposite of suspend()
+ */
+ public void resume() {
+ }
+
+ public void setUpThrottling() {
+ Buffers.getBuffers(BUFDIR).getThrottleManager().register(cb);
+ }
+
+ public void cancelThrottling() {
+ ThrottleManager.getDefault(BUFDIR).unregister(cb);
+ }
}
private static class Reader implements IOReader, ReadBufferCallback {
@@ -125,7 +151,7 @@
cb.length(f.length());
try {
synchronized (this) {
- rbuf = Buffers.newReadBuffer(fc, f.length(), this);
+ rbuf = Buffers.newReadBuffer(Buffers.getBuffers(Direction.IN), fc, f.length(), this);
}
}
catch (InterruptedException e) {
@@ -144,6 +170,10 @@
}
}
+ public void queued() {
+ cb.queued();
+ }
+
private synchronized void closeBuffer() {
try {
rbuf.close();
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/IOWriter.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/IOWriter.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/IOWriter.java (working copy)
@@ -17,4 +17,12 @@
void close() throws IOException;
void write(boolean last, byte[] data) throws IOException;
+
+ void suspend();
+
+ void resume();
+
+ void setUpThrottling();
+
+ void cancelThrottling();
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ProxyIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ProxyIOProvider.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/ProxyIOProvider.java (working copy)
@@ -14,15 +14,22 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
+import java.util.Arrays;
import java.util.LinkedList;
+import java.util.List;
import org.apache.log4j.Logger;
import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Allocation;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBufferCallback;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.ThrottleManager;
import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBuffer;
import org.globus.cog.abstraction.impl.file.coaster.commands.GetFileCommand;
import org.globus.cog.abstraction.impl.file.coaster.commands.PutFileCommand;
+import org.globus.cog.abstraction.impl.file.coaster.handlers.GetFileHandler;
+import org.globus.cog.abstraction.impl.file.coaster.handlers.PutFileHandler;
import org.globus.cog.karajan.workflow.service.ProtocolException;
import org.globus.cog.karajan.workflow.service.channels.ChannelException;
import org.globus.cog.karajan.workflow.service.channels.ChannelManager;
@@ -53,10 +60,20 @@
}
private static class Writer implements IOWriter, Callback {
+ /**
+ * Reverse the buffer direction compared to the local IO provider.
+ * The actual label on the set of buffers is not relevant as long as
+ * they are different on one JVM instance. But when using proxy mode
+ * in local:local (i.e. both service and client in the same JVM) this
+ * avoids a deadlock.
+ */
+ private static Direction BUFDIR = Direction.IN;
+
private CustomPutFileCmd cmd;
private WriteIOCallback cb;
private KarajanChannel channel;
private String src, dst;
+ private boolean done, suspended;
public Writer(String src, String dst, WriteIOCallback cb) throws IOException {
this.cb = cb;
@@ -80,6 +97,16 @@
cmd = new CustomPutFileCmd(src, "file://localhost/" + uri.getPath().substring(1), len, this);
channel = ChannelManager.getManager().reserveChannel("id://" + uri.getHost(), null);
cmd.executeAsync(channel, this);
+ cb.info(String.valueOf(cmd.getId()));
+ synchronized(this) {
+ if (!suspended) {
+ return;
+ }
+ }
+ if (logger.isInfoEnabled()) {
+ logger.info(cmd.getId() + " suspended before. Sending signal.");
+ }
+ cmd.suspend();
}
catch (Exception e) {
throw new IOException(e.getMessage());
@@ -88,6 +115,7 @@
public void write(boolean last, byte[] data) throws IOException {
try {
+ done = last;
cmd.getBuffer().queue(last, ByteBuffer.wrap(data));
}
catch (InterruptedException e) {
@@ -106,11 +134,44 @@
public void abort() throws IOException {
close();
}
+
+ public void suspend() {
+ if (!done) {
+ synchronized(this) {
+ if (cmd == null) {
+ suspended = true;
+ return;
+ }
+ }
+ cmd.suspend();
+ }
+ }
+
+ public void resume() {
+ if (!done) {
+ synchronized(this) {
+ if (cmd == null) {
+ suspended = false;
+ return;
+ }
+ }
+ cmd.resume();
+ }
+ }
+
+ public void setUpThrottling() {
+ Buffers.getBuffers(BUFDIR).getThrottleManager().register(cb);
+ }
+
+ public void cancelThrottling() {
+ ThrottleManager.getDefault(BUFDIR).unregister(cb);
+ }
}
private static class CustomPutFileCmd extends PutFileCommand {
private CReadBuffer buffer;
private Writer handle;
+ private boolean suspended;
public CustomPutFileCmd(String local, String remote, long length, Writer handle) throws IOException,
InterruptedException {
@@ -118,8 +179,31 @@
this.handle = handle;
}
+ public void resume() {
+ synchronized(this) {
+ setLastTime(System.currentTimeMillis());
+ suspended = false;
+ }
+ getChannel().sendTaggedData(getId(), KarajanChannel.SIGNAL_FLAG, PutFileHandler.CONTINUE);
+ }
+
+ public void suspend() {
+ suspended = true;
+ getChannel().sendTaggedData(getId(), KarajanChannel.SIGNAL_FLAG, PutFileHandler.STOP);
+ }
+
+ @Override
+ public synchronized long getLastTime() {
+ if (suspended) {
+ return Long.MAX_VALUE;
+ }
+ else {
+ return super.getLastTime();
+ }
+ }
+
protected ReadBuffer createBuffer() throws FileNotFoundException, InterruptedException {
- return buffer = new CReadBuffer(Buffers.getDefault(), this);
+ return buffer = new CReadBuffer(Buffers.getBuffers(Direction.IN), this);
}
public CReadBuffer getBuffer() {
@@ -137,6 +221,7 @@
}
private static class CReadBuffer extends ReadBuffer {
+
// private Exception error;
// private BlockingQueue queue;
// private boolean seenLast;
@@ -153,17 +238,20 @@
getCallback().error(true, e);
}
- public synchronized void queue(boolean last, ByteBuffer buf) throws InterruptedException {
- while (crt >= Buffers.ENTRIES_PER_STREAM) {
- wait();
+ public void queue(boolean last, ByteBuffer buf) throws InterruptedException {
+ if (logger.isDebugEnabled()) {
+ logger.debug(getCallback() + " got data");
}
- crt++;
- alloc.add(buffers.request(1));
- /* if (last) {
- seenLast = true;
- } */
+ Buffers.Allocation a = buffers.request(1);
+ synchronized(this) {
+ crt++;
+ alloc.add(a);
+ /* if (last) {
+ seenLast = true;
+ } */
+ }
getCallback().dataRead(last, buf);
- }
+ }
public synchronized void freeFirst() {
buffers.free(alloc.removeFirst());
@@ -174,7 +262,7 @@
protected void deallocateBuffers() {
}
- public void doStuff(boolean last, ByteBuffer b) {
+ public void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc) {
// not used
}
}
@@ -223,6 +311,7 @@
logger.debug("Sending proxy get");
cmd.executeAsync(channel, this);
logger.debug("Proxy get sent");
+ cb.info(String.valueOf(cmd.getId()));
}
catch (ProtocolException e) {
logger.warn("Error requesting file from " + channel, e);
@@ -249,6 +338,7 @@
}
public void dataSent() {
+ cmd.cwb.releaseOne();
}
public void errorReceived(Command cmd, String msg, Exception t) {
@@ -273,6 +363,7 @@
private static class CustomGetFileCmd extends GetFileCommand {
private final ReadIOCallback cb;
private final Reader handle;
+ public CWriteBuffer cwb;
public CustomGetFileCmd(String src, String dst, Reader handle) throws IOException {
super(src, dst, null);
@@ -284,24 +375,42 @@
}
protected WriteBuffer createWriteBuffer() throws IOException {
- return new CWriteBuffer(Buffers.getDefault(), this);
+ return cwb = new CWriteBuffer(Buffers.getBuffers(Direction.OUT), this);
}
protected void setLen(long len) {
super.setLen(len);
cb.length(len);
}
+
+ @Override
+ public void handleSignal(byte[] data) {
+ if (Arrays.equals(GetFileHandler.QUEUED.getBytes(), data)) {
+ setQueued(true);
+ cb.queued();
+ }
+ }
}
private static class CWriteBuffer extends WriteBuffer {
private final CustomGetFileCmd cmd;
+ public List<Allocation> alloc;
protected CWriteBuffer(Buffers buffers, CustomGetFileCmd cmd) {
super(buffers);
this.cmd = cmd;
+ alloc = new LinkedList<Allocation>();
}
- public void doStuff(boolean last, ByteBuffer b) {
+ public void releaseOne() {
+ Allocation a;
+ synchronized(alloc) {
+ a = alloc.remove(0);
+ }
+ buffers.free(a);
+ }
+
+ public void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc) {
try {
cmd.cb.data(cmd.handle, b, last);
}
@@ -309,6 +418,14 @@
e.printStackTrace();
}
}
+
+ public void write(boolean last, byte[] data) throws InterruptedException {
+ Allocation a = buffers.request(1);
+ synchronized(alloc) {
+ alloc.add(a);
+ }
+ buffers.queueRequest(last, ByteBuffer.wrap(data), this);
+ }
private byte[] getByteArray(ByteBuffer b) {
if (b.hasArray()) {
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalCopyIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalCopyIOProvider.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalCopyIOProvider.java (working copy)
@@ -110,5 +110,21 @@
super(src, getPath(dest), cb);
start();
}
+
+ public void suspend() {
+ // not used
+ }
+
+ public void resume() {
+ // not used
+ }
+
+ public void setUpThrottling() {
+ // not used
+ }
+
+ public void cancelThrottling() {
+ // not used
+ }
}
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalIOProvider.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalIOProvider.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/handlers/providers/LocalIOProvider.java (working copy)
@@ -22,8 +22,10 @@
import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBufferCallback;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.ThrottleManager;
import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBufferCallback;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
import org.globus.cog.abstraction.impl.file.coaster.handlers.CoasterFileRequestHandler;
public class LocalIOProvider implements IOProvider {
@@ -55,6 +57,8 @@
}
private static class Writer implements IOWriter, WriteBufferCallback, Abortable {
+ private static Direction BUFDIR = Direction.OUT;
+
private File f;
private long len, crt;
private WriteIOCallback cb;
@@ -86,7 +90,7 @@
throw new IOException("Failed to create directory " + p.getAbsolutePath());
}
}
- buf = Buffers.newWriteBuffer(new FileOutputStream(f).getChannel(), this);
+ buf = Buffers.newWriteBuffer(Buffers.getBuffers(Direction.OUT), new FileOutputStream(f).getChannel(), this);
}
}
@@ -118,6 +122,22 @@
buf.close();
f.delete();
}
+
+ public void suspend() {
+ // not used
+ }
+
+ public void resume() {
+ // not used
+ }
+
+ public void setUpThrottling() {
+ Buffers.getBuffers(BUFDIR).getThrottleManager().register(cb);
+ }
+
+ public void cancelThrottling() {
+ ThrottleManager.getDefault(BUFDIR).unregister(cb);
+ }
}
private static class Reader implements IOReader, ReadBufferCallback {
@@ -142,7 +162,7 @@
cb.length(f.length());
try {
synchronized(this) {
- rbuf = Buffers.newReadBuffer(fc, f.length(), this);
+ rbuf = Buffers.newReadBuffer(Buffers.getBuffers(Direction.IN), fc, f.length(), this);
}
}
catch (InterruptedException e) {
@@ -151,6 +171,7 @@
}
public synchronized void dataSent() {
+ logger.debug("Data sent");
rbuf.freeFirst();
}
@@ -161,6 +182,10 @@
}
}
+ public void queued() {
+ cb.queued();
+ }
+
private synchronized void closeBuffer() {
try {
rbuf.close();
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/commands/PutFileCommand.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/commands/PutFileCommand.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/commands/PutFileCommand.java (working copy)
@@ -19,6 +19,7 @@
import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.ReadBufferCallback;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
import org.globus.cog.karajan.workflow.service.ProtocolException;
import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
import org.globus.cog.karajan.workflow.service.commands.Command;
@@ -27,6 +28,7 @@
public static final Logger logger = Logger.getLogger(PutFileCommand.class);
public static final String NAME = "PUT";
+ public static final String QUEUED = "QUEUED";
private String dest;
private long size;
@@ -34,6 +36,7 @@
private ReadBuffer rbuf;
// private Exception ex;
private String src;
+ private boolean done;
public PutFileCommand(String src, String dest) throws IOException, InterruptedException {
this(src, dest, new File(src).length());
@@ -50,7 +53,7 @@
}
protected ReadBuffer createBuffer() throws FileNotFoundException, InterruptedException {
- return Buffers.newReadBuffer(new FileInputStream(src).getChannel(), size, this);
+ return Buffers.newReadBuffer(Buffers.getBuffers(Direction.OUT), new FileInputStream(src).getChannel(), size, this);
}
public void send() throws ProtocolException {
@@ -61,27 +64,46 @@
if (channel == null) {
throw new ProtocolException("Unregistered command");
}
+
+ long now = System.currentTimeMillis();
+ setSendReqTime(now);
+ setLastTime(now);
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + ", src: " + src + ", dest: " + dest + ", size: " + size);
+ }
channel.sendTaggedData(getId(), false, getOutCmd().getBytes());
channel.sendTaggedData(getId(), false, pack(size));
channel.sendTaggedData(getId(), false, src.getBytes());
channel.sendTaggedData(getId(), size == 0, dest.getBytes());
if (logger.isInfoEnabled()) {
- logger.info("Sending data");
+ logger.info(this + " sending data");
}
}
public void dataSent() {
+ super.dataSent();
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " data sent");
+ }
rbuf.freeFirst();
}
public void dataRead(boolean last, ByteBuffer buf) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(this + " data read, last = " + last);
+ }
getChannel().sendTaggedData(getId(), last ? KarajanChannel.FINAL_FLAG : 0, buf, this);
if (last) {
+ done = true;
closeBuffer();
}
}
+ public void queued() {
+ getChannel().sendTaggedData(getId(), KarajanChannel.SIGNAL_FLAG, QUEUED.getBytes());
+ }
+
private void closeBuffer() {
try {
rbuf.close();
@@ -95,4 +117,8 @@
getChannel().sendTaggedReply(getId(), e.getMessage().getBytes(), true, true, null);
closeBuffer();
}
+
+ public String toString() {
+ return super.toString() + (done ? " (d)" : " (t)");
+ }
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/commands/GetFileCommand.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/commands/GetFileCommand.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/commands/GetFileCommand.java (working copy)
@@ -11,11 +11,14 @@
import java.io.FileOutputStream;
import java.io.IOException;
+import java.util.Arrays;
import org.apache.log4j.Logger;
import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBuffer;
import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBufferCallback;
-import org.globus.cog.abstraction.impl.file.coaster.buffers.WriteBuffer;
+import org.globus.cog.abstraction.impl.file.coaster.handlers.GetFileHandler;
import org.globus.cog.abstraction.interfaces.ProgressMonitor;
import org.globus.cog.karajan.workflow.service.commands.Command;
@@ -25,6 +28,7 @@
private long len = -1;
private WriteBuffer wt;
private String dst;
+ private boolean queued;
// private ProgressMonitor pm;
public GetFileCommand(String src, String dst, ProgressMonitor pm)
@@ -41,10 +45,11 @@
}
protected WriteBuffer createWriteBuffer() throws IOException {
- return Buffers.newWriteBuffer(new FileOutputStream(dst).getChannel(), this);
+ return Buffers.newWriteBuffer(Buffers.getBuffers(Direction.IN), new FileOutputStream(dst).getChannel(), this);
}
protected void addInData(boolean fin, boolean err, byte[] data) {
+ queued = false;
if (err) {
super.addInData(fin, err, data);
}
@@ -84,6 +89,30 @@
}
}
+ @Override
+ public void handleSignal(byte[] data) {
+ if (Arrays.equals(GetFileHandler.QUEUED.getBytes(), data)) {
+ setQueued(true);
+ }
+ }
+
+ protected void setQueued(boolean queued) {
+ if (logger.isInfoEnabled()) {
+ logger.info(this + " queued");
+ }
+ this.queued = queued;
+ }
+
+ @Override
+ public long getLastTime() {
+ if (queued) {
+ return Long.MAX_VALUE;
+ }
+ else {
+ return super.getLastTime();
+ }
+ }
+
public void error(boolean last, Exception e) {
this.errorReceived("Failed to write file data", e);
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ThrottleManager.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ThrottleManager.java (revision 0)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ThrottleManager.java (revision 3355)
@@ -0,0 +1,140 @@
+//----------------------------------------------------------------------
+//This code is developed as part of the Java CoG Kit project
+//The terms of the license can be found at http://www.cogkit.org/license
+//This message may not be removed or altered.
+//----------------------------------------------------------------------
+
+/*
+ * Created on Oct 14, 2011
+ */
+package org.globus.cog.abstraction.impl.file.coaster.buffers;
+
+import java.util.Stack;
+
+import org.apache.log4j.Logger;
+import org.globus.cog.abstraction.impl.file.coaster.buffers.Buffers.Direction;
+import org.globus.cog.abstraction.impl.file.coaster.handlers.PutFileHandler;
+import org.globus.cog.abstraction.impl.file.coaster.handlers.providers.WriteIOCallback;
+import org.globus.cog.karajan.workflow.service.channels.PerformanceDiagnosticInputStream;
+
+public class ThrottleManager {
+ public static final Logger logger = Logger.getLogger(ThrottleManager.class);
+
+ private static final ThrottleManager IN = new ThrottleManager(Direction.IN);
+ private static final ThrottleManager OUT = new ThrottleManager(Direction.OUT);
+
+ public static final int MAX_CONCURRENT_TRANSFERS = 256;
+ public static final double LAMBDA = 3;
+
+ public static final long MIN_UPDATE_INTERVAL = 500; //ms
+
+ /*
+ * lambda = 0.2 gives a nice curve like this:
+ * http://www.wolframalpha.com/input/?i=plot+256*exp%28-0.2*%28x%2F%28512-x%2B0.0001%29%29%29%2C+x+%3D+0+to+512
+ */
+
+ public static ThrottleManager getDefault(Direction dir) {
+ switch (dir) {
+ case IN: return IN;
+ case OUT: return OUT;
+ default: return null;
+ }
+ }
+
+ private Stack<WriteIOCallback> active, suspended;
+ private long lastTime;
+ private int lastMaxTransfers;
+ private Direction dir;
+
+ public ThrottleManager(Direction dir) {
+ this.dir = dir;
+ active = new Stack<WriteIOCallback>();
+ suspended = new Stack<WriteIOCallback>();
+ lastTime = System.currentTimeMillis();
+ lastMaxTransfers = MAX_CONCURRENT_TRANSFERS;
+ }
+
+ public void register(WriteIOCallback cb) {
+ synchronized(this) {
+ if (active.size() > lastMaxTransfers) {
+ cb.suspend();
+ // put this at the bottom of the stack, so earlier transfers
+ // get priority
+ suspended.insertElementAt(cb, 0);
+ }
+ else {
+ active.push(cb);
+ }
+ }
+ }
+
+ public void unregister(WriteIOCallback cb) {
+ synchronized(this) {
+ if (!active.remove(cb)) {
+ suspended.remove(cb);
+ }
+ }
+ }
+
+ public void update(int maxBuffers, int crtBuffers) {
+ long now = System.currentTimeMillis();
+ if (now - lastTime < MIN_UPDATE_INTERVAL) {
+ return;
+ }
+ lastTime = now;
+ int allowed = allowedTransfers(maxBuffers, crtBuffers);
+ log(allowed, maxBuffers, crtBuffers);
+ // Use stacks because of the assumption that it's better to have
+ // some transfers prioritized
+ synchronized(this) {
+ while (active.size() > allowed) {
+ suspendOne();
+ }
+ while (active.size() < allowed && !suspended.isEmpty()) {
+ resumeOne();
+ }
+ }
+ }
+
+ private void log(int allowed, int maxBuffers, int crtBuffers) {
+ if (logger.isInfoEnabled()) {
+ logger.info(dir + " maxBuffers=" + maxBuffers + ", crtBuffers=" + crtBuffers +
+ ", allowedTransfers=" + allowed + ", active=" + active.size() +
+ ", suspended=" + suspended.size());
+ Runtime r = Runtime.getRuntime();
+ if (dir == Direction.OUT) {
+ logger.info("mem=" + PerformanceDiagnosticInputStream.units(r.totalMemory() - r.freeMemory()) +
+ "B, heap=" + PerformanceDiagnosticInputStream.units(r.totalMemory()) +
+ "B, maxHeap=" + PerformanceDiagnosticInputStream.units(r.maxMemory()) + "B");
+ }
+ }
+ }
+
+ private void suspendOne() {
+ WriteIOCallback h = active.pop();
+ h.suspend();
+ suspended.push(h);
+ }
+
+ private void resumeOne() {
+ WriteIOCallback h = suspended.pop();
+ h.resume();
+ active.push(h);
+ }
+
+ private int allowedTransfers(int maxBuffers, int crtBuffers) {
+ // 0 when crtBuffers = maxBuffers
+ // MAX_CONCURRENT_TRANSFERS when crtBuffers = 0
+ // some smooth function in between
+ // the 0.0001 is there to approximate +inf when maxBuffers = crtBuffers.
+ if (maxBuffers < crtBuffers) {
+ return 0;
+ }
+ int allowed = (int) Math.round(MAX_CONCURRENT_TRANSFERS *
+ Math.exp(-LAMBDA * (crtBuffers/(maxBuffers - crtBuffers + 0.0001))));
+ if (allowed < 0) {
+ allowed = 0;
+ }
+ return allowed;
+ }
+}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/InputStreamReadBuffer.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/InputStreamReadBuffer.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/InputStreamReadBuffer.java (working copy)
@@ -25,14 +25,14 @@
init();
}
- public void doStuff(boolean last, ByteBuffer b) {
+ public void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc) {
if (read >= size) {
return;
}
+ if (alloc != null) {
+ bufferCreated(alloc);
+ }
try {
- if (b == null) {
- b = allocateOneBuffer();
- }
if (b.hasArray()) {
int len = is.read(b.array());
b.limit(len);
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/OutputStreamWriteBuffer.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/OutputStreamWriteBuffer.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/OutputStreamWriteBuffer.java (working copy)
@@ -24,7 +24,7 @@
this.cb = cb;
}
- public void doStuff(boolean last, ByteBuffer b) {
+ public void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc) {
try {
os.write(toByteArray(b));
b.rewind();
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ReadBufferCallback.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ReadBufferCallback.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ReadBufferCallback.java (working copy)
@@ -15,4 +15,6 @@
void dataRead(boolean last, ByteBuffer buf);
void error(boolean last, Exception e);
+
+ void queued();
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/NIOChannelWriteBuffer.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/NIOChannelWriteBuffer.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/NIOChannelWriteBuffer.java (working copy)
@@ -24,14 +24,14 @@
this.cb = cb;
}
- public void doStuff(boolean last, ByteBuffer b) {
+ public void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc) {
try {
channel.write(b);
b.rewind();
- cb.done(last);
if (last) {
channel.close();
}
+ cb.done(last);
}
catch (IOException e) {
cb.error(last, e);
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/NIOChannelReadBuffer.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/NIOChannelReadBuffer.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/NIOChannelReadBuffer.java (working copy)
@@ -13,7 +13,11 @@
import java.nio.ByteBuffer;
import java.nio.channels.ScatteringByteChannel;
+import org.apache.log4j.Logger;
+
public class NIOChannelReadBuffer extends ReadBuffer {
+ public static final Logger logger = Logger.getLogger(NIOChannelReadBuffer.class);
+
private ScatteringByteChannel channel;
private long crt;
private Exception ex;
@@ -25,14 +29,20 @@
init();
}
- public void doStuff(boolean last, ByteBuffer b) {
+ public void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc) {
if (read >= size) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Transfer done. De-allocating one unused buffer");
+ }
+ if (alloc != null) {
+ buffers.free(alloc);
+ }
return;
}
+ if (alloc != null) {
+ bufferCreated(alloc);
+ }
try {
- if (b == null) {
- b = allocateOneBuffer();
- }
channel.read(b);
b.limit(b.position());
b.rewind();
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ReadBuffer.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ReadBuffer.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/ReadBuffer.java (working copy)
@@ -11,17 +11,23 @@
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.List;
+import org.apache.log4j.Logger;
+
public abstract class ReadBuffer extends Buffer {
+ public static final Logger logger = Logger.getLogger(ReadBuffer.class);
+
private final ReadBufferCallback cb;
protected LinkedList<ByteBuffer> full;
protected LinkedList<ByteBuffer> empty;
protected long read;
protected long size;
- protected Buffers.Allocation alloc;
+ protected List<Buffers.Allocation> allocs;
protected ReadBuffer(Buffers buffers, ReadBufferCallback cb, long size) {
super(buffers);
@@ -36,21 +42,25 @@
protected void init() throws InterruptedException {
full = new LinkedList<ByteBuffer>();
empty = new LinkedList<ByteBuffer>();
- for (int i = 0; i < Buffers.ENTRIES_PER_STREAM; i++) {
+ allocs = new ArrayList<Buffers.Allocation>();
+
+ int nbuf = Math.min((int) (size / Buffers.ENTRY_SIZE) + 1, Buffers.ENTRIES_PER_STREAM);
+
+ if (logger.isInfoEnabled()) {
+ logger.info("Will ask for " + nbuf + " buffers for a size of " + size);
+ }
+
+ for (int i = 0; i < nbuf; i++) {
// these will be allocated when the first read happens,
// which also happens to happen in the I/O thread
empty.add(null);
}
- requestFill();
+ if (requestFill() == nbuf) {
+ // all buffers are queued
+ cb.queued();
+ }
}
- protected ByteBuffer allocateOneBuffer() throws InterruptedException {
- if (alloc == null) {
- alloc = buffers.request(Buffers.ENTRIES_PER_STREAM);
- }
- return ByteBuffer.allocate(Buffers.ENTRY_SIZE);
- }
-
public void freeFirst() {
ByteBuffer b;
synchronized (this) {
@@ -61,16 +71,20 @@
requestFill();
}
- protected void requestFill() {
+ protected int requestFill() {
+ int queued = 0;
synchronized (empty) {
while (!empty.isEmpty() && read < size) {
ByteBuffer buf = empty.removeFirst();
if (buf != null) {
buf.clear();
}
- buffers.queueRequest(false, buf, this);
+ if (buffers.queueRequest(false, buf, this)) {
+ queued++;
+ }
}
}
+ return queued;
}
public void error(ByteBuffer buf, Exception e) {
@@ -88,8 +102,20 @@
getCallback().dataRead(read == size, buf);
}
+ protected void bufferCreated(Buffers.Allocation a) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("buffer created");
+ }
+ allocs.add(a);
+ }
+
protected void deallocateBuffers() {
- buffers.free(alloc);
+ if (logger.isInfoEnabled()) {
+ logger.info("De-allocating " + allocs.size() + " buffers");
+ }
+ for (Buffers.Allocation a : allocs) {
+ buffers.free(a);
+ }
}
public void close() throws IOException {
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/Buffer.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/Buffer.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/Buffer.java (working copy)
@@ -18,7 +18,7 @@
this.buffers = buffers;
}
- public abstract void doStuff(boolean last, ByteBuffer b);
+ public abstract void doStuff(boolean last, ByteBuffer b, Buffers.Allocation alloc);
public void close() throws IOException {
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/Buffers.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/Buffers.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/file/coaster/buffers/Buffers.java (working copy)
@@ -23,24 +23,51 @@
public static final int ENTRY_SIZE = 32768;
public static final int ENTRIES_PER_STREAM = 16;
- public static final int MAX_ENTRIES = 256;
+ public static final int MAX_ENTRIES = 512; // 16 MB
public static final int PERFORMANCE_LOGGING_INTERVAL = 10000;
+
+ public static enum Direction {
+ IN("I"), OUT("O");
+
+ private String name;
+
+ Direction(String name) {
+ this.name = name;
+ }
- private static final Buffers INSTANCE = new Buffers();
+ @Override
+ public String toString() {
+ return name;
+ }
+ }
+ private static final Buffers OUTB = new Buffers(Direction.OUT);
+ private static final Buffers INB = new Buffers(Direction.IN);
+
private LinkedList<Entry> queue;
+ private LinkedList<Entry> waiting;
+
private Object sizeLock = new Object();
private int crt;
private long lastTime, bufTime;
private double avgBuffersUsed;
private int maxBuffersUsed, minBuffersUsed;
+ private Direction dir;
+ private ThrottleManager throttleManager;
- public Buffers() {
+ public Buffers(Direction dir) {
+ this.dir = dir;
+ this.throttleManager = ThrottleManager.getDefault(dir);
queue = new LinkedList<Entry>();
+ waiting = new LinkedList<Entry>();
setName("I/O Queue");
setDaemon(true);
start();
}
+
+ public ThrottleManager getThrottleManager() {
+ return throttleManager;
+ }
public synchronized void start() {
super.start();
@@ -55,42 +82,41 @@
maxBuffersUsed = 0;
}
- public static ReadBuffer newReadBuffer(ScatteringByteChannel channel, long size,
+ public static ReadBuffer newReadBuffer(Buffers buffers, ScatteringByteChannel channel, long size,
ReadBufferCallback cb) throws InterruptedException {
- return new NIOChannelReadBuffer(INSTANCE, channel, size, cb);
+ return new NIOChannelReadBuffer(buffers, channel, size, cb);
}
- public static ReadBuffer newReadBuffer(InputStream is, long size, ReadBufferCallback cb)
+ public static ReadBuffer newReadBuffer(Buffers buffers, InputStream is, long size, ReadBufferCallback cb)
throws InterruptedException {
- return new InputStreamReadBuffer(INSTANCE, is, size, cb);
+ return new InputStreamReadBuffer(buffers, is, size, cb);
}
- public static WriteBuffer newWriteBuffer(GatheringByteChannel channel, WriteBufferCallback cb) {
- return new NIOChannelWriteBuffer(INSTANCE, channel, cb);
+ public static WriteBuffer newWriteBuffer(Buffers buffers, GatheringByteChannel channel, WriteBufferCallback cb) {
+ return new NIOChannelWriteBuffer(buffers, channel, cb);
}
- public static WriteBuffer newWriteBuffer(OutputStream os, WriteBufferCallback cb) {
- return new OutputStreamWriteBuffer(INSTANCE, os, cb);
+ public static WriteBuffer newWriteBuffer(Buffers buffers, OutputStream os, WriteBufferCallback cb) {
+ return new OutputStreamWriteBuffer(buffers, os, cb);
}
- public synchronized void queueRequest(boolean last, ByteBuffer buf, Buffer buffer) {
- queue.add(new Entry(last, buf, buffer));
- notify();
- }
-
- public Allocation request(int count) throws InterruptedException {
- synchronized (sizeLock) {
- while (crt + count > MAX_ENTRIES) {
- sizeLock.wait(1000);
+ public synchronized boolean queueRequest(boolean last, ByteBuffer buf, Buffer buffer) {
+ Entry e = new Entry(last, buf, buffer);
+ if (buf == null && crt > MAX_ENTRIES) {
+ waiting.add(e);
+ return true;
+ }
+ else {
+ queue.add(e);
+ if (buf == null) {
+ // not a pre-allocated buffer
+ crt++;
}
- updateBuffersUsed();
- crt += count;
- Allocation a = new Allocation(count);
- assert(!a.free);
- return a;
+ notify();
+ return false;
}
}
-
+
private void updateBuffersUsed() {
long time = System.currentTimeMillis();
avgBuffersUsed += (time - bufTime) * crt;
@@ -102,41 +128,71 @@
}
bufTime = time;
}
-
- public void free(Allocation alloc) {
- synchronized (sizeLock) {
- if (alloc == null) {
- throw new IllegalArgumentException("Null alloc");
+
+ public synchronized Allocation request(int count) throws InterruptedException {
+ if (logger.isDebugEnabled()) {
+ logger.debug(dir + " request " + count + ", crt = " + crt + ", max = " + MAX_ENTRIES);
+ }
+ while (crt >= MAX_ENTRIES) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(dir + " max buffers reached. Waiting...");
}
- if (alloc.free) {
- logger.warn("Trying to release buffer allocation twice", new Exception());
- return;
- }
- updateBuffersUsed();
- crt -= alloc.count;
- alloc.free();
- sizeLock.notify();
+ wait();
}
+ updateBuffersUsed();
+ crt += count;
+ return new Allocation(count);
}
+
+ public synchronized void free(Allocation alloc) {
+ if (alloc == null) {
+ throw new IllegalArgumentException("Null alloc");
+ }
+ if (alloc.free) {
+ logger.warn(dir + " trying to release buffer allocation twice", new Exception());
+ return;
+ }
+ if (logger.isDebugEnabled()) {
+ logger.debug(dir + " free " + alloc.count + ", crt = " + crt + ", max = " + MAX_ENTRIES);
+ }
+ updateBuffersUsed();
+ crt -= alloc.count;
+ alloc.free();
+ queueWaiting();
+ notify();
+ }
+ private void queueWaiting() {
+ while (!waiting.isEmpty() && crt < MAX_ENTRIES) {
+ queue.add(waiting.removeFirst());
+ crt++;
+ }
+ }
+
public void run() {
try {
while (true) {
Entry e;
synchronized (this) {
while (queue.isEmpty()) {
- this.wait();
+ this.wait(ThrottleManager.MIN_UPDATE_INTERVAL);
+ throttleManager.update(MAX_ENTRIES, crt);
}
e = queue.removeFirst();
}
try {
- e.buffer.doStuff(e.last, e.buf);
+ if (e.buf == null) {
+ e.buffer.doStuff(e.last, ByteBuffer.allocate(ENTRY_SIZE), new Allocation(1));
+ }
+ else {
+ e.buffer.doStuff(e.last, e.buf, null);
+ }
if (logger.isInfoEnabled()) {
long time = System.currentTimeMillis();
long dif = time - lastTime;
if (dif > PERFORMANCE_LOGGING_INTERVAL) {
int avgbuf = (int) (avgBuffersUsed / dif);
- logger.info("elapsedTime=" + dif + ", buffersUsed[min,avg,max]="
+ logger.info(dir + " elapsedTime=" + dif + ", buffersUsed[min,avg,max]="
+ minBuffersUsed + ", " + avgbuf + ", " + maxBuffersUsed);
resetCounters();
}
@@ -176,7 +232,11 @@
}
}
- public static Buffers getDefault() {
- return INSTANCE;
+ public static Buffers getBuffers(Direction dir) {
+ switch(dir) {
+ case IN: return INB;
+ case OUT: return OUTB;
+ default: return null;
+ }
}
}
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/JobSubmissionTaskHandler.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/JobSubmissionTaskHandler.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/JobSubmissionTaskHandler.java (working copy)
@@ -7,7 +7,9 @@
package org.globus.cog.abstraction.impl.execution.coaster;
import java.io.IOException;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Map;
import java.util.Random;
import java.util.Set;
@@ -45,6 +47,9 @@
private static Logger logger = Logger.getLogger(JobSubmissionTaskHandler.class);
private static Set<Object> configured, configuring;
+
+ private static Map<Service, TaskSubmissionException> checkedServices =
+ new HashMap<Service, TaskSubmissionException>();
static {
configured = new HashSet<Object>();
@@ -94,6 +99,7 @@
public void submit(Task task) throws IllegalSpecException, InvalidSecurityContextException,
InvalidServiceContactException, TaskSubmissionException {
checkAndSetTask(task);
+ validateTaskSettings();
task.setStatus(Status.SUBMITTING);
try {
KarajanChannel channel = getChannel(task);
@@ -257,7 +263,118 @@
public void setAutostart(boolean autostart) {
this.autostart = autostart;
}
+
+ private void validateTaskSettings() throws TaskSubmissionException {
+ synchronized (JobSubmissionTaskHandler.class) {
+ Task task = getTask();
+ Service s = task.getService(0);
+ TaskSubmissionException e = checkedServices.get(s);
+ if (e != null) {
+ throw e;
+ }
+ else if (!checkedServices.containsKey(s)) {
+ try {
+ validateTask();
+ }
+ catch (IllegalArgumentException ee) {
+ e = new TaskSubmissionException(ee.getMessage());
+ checkedServices.put(task.getService(0), e);
+ throw e;
+ }
+ }
+ }
+ }
+
+ private void validateTask() {
+ checkPositiveInt("slots", 0);
+ checkPositiveInt("maxNodes", 0);
+ checkPositiveInt("maxTime", 0);
+ Integer nodeGranularity = getInt("nodeGranularity");
+ Integer maxNodes = getInt("maxNodes");
+ if (nodeGranularity != null && maxNodes != null) {
+ if (nodeGranularity > maxNodes) {
+ throw new IllegalArgumentException("nodeGranularity > maxNodes (" +
+ nodeGranularity + " > " + maxNodes + ")");
+ }
+ }
+
+ checkGreaterOrEqualThan("lowOverallocation", 1);
+ checkGreaterThan("highOverallocation", 1);
+
+ checkGreaterThan("allocationStepSize", 0);
+ checkLessOrEqualThan("allocationStepSize", 1);
+
+ checkGreaterOrEqualThan("spread", 0);
+ checkLessOrEqualThan("spread", 1);
+
+ checkGreaterOrEqualThan("parallelism", 0);
+ checkLessOrEqualThan("parallelism", 1);
+ }
+ private void checkPositiveInt(String name, int i) {
+ Integer v = getInt(name);
+ if (v != null && v <= 0) {
+ throw new IllegalArgumentException(name + " must be > 0 (currently " + v + ")");
+ }
+ }
+
+ private void checkGreaterOrEqualThan(String name, double d) {
+ Double v = getDouble(name);
+ if (v != null && v < d) {
+ throw new IllegalArgumentException(name + " must be >= " + d + " (currently " + v + ")");
+ }
+ }
+
+ private void checkLessOrEqualThan(String name, double d) {
+ Double v = getDouble(name);
+ if (v != null && v > d) {
+ throw new IllegalArgumentException(name + " must be <= " + d + " (currently " + v + ")");
+ }
+ }
+
+ private void checkLessThan(String name, double d) {
+ Double v = getDouble(name);
+ if (v != null && v >= d) {
+ throw new IllegalArgumentException(name + " must be < " + d + " (currently " + v + ")");
+ }
+ }
+
+ private void checkGreaterThan(String name, double d) {
+ Double v = getDouble(name);
+ if (v != null && v <= d) {
+ throw new IllegalArgumentException(name + " must be > " + d + " (currently " + v + ")");
+ }
+ }
+
+ private Double getDouble(String name) {
+ Object v = ((JobSpecification) getTask().getSpecification()).getAttribute(name.toLowerCase());
+ if (v == null) {
+ return null;
+ }
+ else if (v instanceof String) {
+ return Double.parseDouble((String) v);
+ }
+ else if (v instanceof Number) {
+ return ((Number) v).doubleValue();
+ }
+ else {
+ throw new IllegalArgumentException("Invalid valid for " + name + ": " + v + "; must be a floating point number.");
+ }
+ }
+
+ private Integer getInt(String name) {
+ Object v = ((JobSpecification) getTask().getSpecification()).getAttribute(name.toLowerCase());
+ if (v == null) {
+ return null;
+ }
+ else if (v instanceof String) {
+ return Integer.parseInt((String) v);
+ }
+ else {
+ throw new IllegalArgumentException("Invalid valid for " + name + ": " + v + "; must be an integer.");
+ }
+ }
+
private static Task submitTask() throws Exception {
Task t = new TaskImpl();
t.setType(Task.JOB_SUBMISSION);
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/PackageList.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/PackageList.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/PackageList.java (working copy)
@@ -26,7 +26,6 @@
if (!dir.exists()) {
throw new RuntimeException(dir + " does not exist");
}
- add("backport-util-concurrent.jar");
add("cog-abstraction-common-*.jar");
add("cog-jglobus-*.jar");
add("cog-karajan-*.jar");
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/ServiceManager.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/ServiceManager.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/ServiceManager.java (working copy)
@@ -226,6 +226,9 @@
String msg =
"Coaster service ended. Reason: " + s.getMessage() + "\n\tstdout: "
+ t.getStdOutput() + "\n\tstderr: " + t.getStdError();
+ if (logger.isInfoEnabled()) {
+ logger.info(msg);
+ }
NotificationManager.getDefault().serviceTaskEnded(contact, msg);
try {
if (url != null) {
@@ -431,7 +434,7 @@
ChannelManager.getManager().reserveChannel(url, (GSSCredential) cred);
logger.debug("Got channel " + channel);
ServiceShutdownCommand ssc = new ServiceShutdownCommand();
- ssc.setReplyTimeout(10000);
+ ssc.setTimeout(10000);
ssc.setMaxRetries(0);
ssc.executeAsync(channel, this);
ChannelManager.getManager().releaseChannel(channel);
Index: modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/bootstrap/Bootstrap.java
===================================================================
--- modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/bootstrap/Bootstrap.java (revision 3354)
+++ modules/provider-coaster/src/org/globus/cog/abstraction/impl/execution/coaster/bootstrap/Bootstrap.java (working copy)
@@ -17,7 +17,6 @@
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
-import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -25,10 +24,7 @@
import java.util.Iterator;
import java.util.List;
-import org.globus.cog.abstraction.impl.execution.coaster.BootstrapService;
-import org.globus.cog.abstraction.impl.execution.coaster.ServiceManager;
-
public class Bootstrap {
public static final boolean fork = true;
@@ -53,14 +49,14 @@
private String serviceURL;
private String registrationURL;
private String serviceId;
- private List list;
+ private List<String[]> list;
public Bootstrap(String serviceURL,
String registrationURL, String serviceId) {
this.serviceURL = serviceURL;
this.registrationURL = registrationURL;
this.serviceId = serviceId;
- list = new ArrayList();
+ list = new ArrayList<String[]>();
logger = new Logger(serviceId);
}
@@ -105,9 +101,9 @@
if (!CACHE_DIR.mkdirs() && !CACHE_DIR.exists()) {
error("Could not create jar cache directory");
}
- Iterator i = list.iterator();
+ Iterator<String[]> i = list.iterator();
while (i.hasNext()) {
- String[] jar = (String[]) i.next();
+ String[] jar = i.next();
File f = new File(CACHE_DIR, buildName(jar));
if (!f.exists()) {
download(CACHE_DIR, jar[0], jar[1]);
@@ -155,9 +151,9 @@
private void arrangeJars() {
String[] coasterJar = null;
- Iterator i = list.iterator();
+ Iterator<String[]> i = list.iterator();
while (i.hasNext()) {
- coasterJar = (String[]) i.next();
+ coasterJar = i.next();
if (coasterJar[0].indexOf("provider-coaster") != -1) {
i.remove();
break;
@@ -173,23 +169,24 @@
logger.log("Forking service");
StringBuffer sb = new StringBuffer();
arrangeJars();
- Iterator i = list.iterator();
+ Iterator<String[]> i = list.iterator();
while (i.hasNext()) {
sb.append(CACHE_DIR.getAbsolutePath());
sb.append('/');
- sb.append(buildName((String[]) i.next()));
+ sb.append(buildName(i.next()));
if (i.hasNext()) {
sb.append(':');
}
}
String java = System.getProperty("java");
- List args = new ArrayList();
+ List<String> args = new ArrayList<String>();
args.add("nice");
args.add("-n");
args.add("2");
args.add(java);
addDebuggingOptions(args);
args.add("-Xmx256M");
+ args.add("-Dtcp.channel.log.io.performance=true");
//args.add("-agentlib:hprof=file=c.hprof");
addProperties(args);
args.add("-cp");
@@ -198,8 +195,7 @@
args.add(registrationURL);
args.add(serviceId);
logger.log("Args: " + args);
- Process p = Runtime.getRuntime().exec(
- (String[]) args.toArray(new String[0]));
+ Process p = Runtime.getRuntime().exec(args.toArray(new String[0]));
StringBuffer out = new StringBuffer(), err = new StringBuffer();
logger.log("Starting stdout consumer");
consumeOutput(p.getInputStream(), out);
@@ -223,13 +219,13 @@
}
}
- private void addDebuggingOptions(List args) {
+ private void addDebuggingOptions(List<String> args) {
//args.add("-Xdebug");
//args.add("-Xrunjdwp:transport=dt_socket,address=8788,server=y,suspend=y");
//args.add("-Xrunjdwp:transport=dt_socket,address=8788,server=y,suspend=n");
}
- private void addProperties(List args) {
+ private void addProperties(List<String> args) {
addProperty(args, "X509_USER_PROXY");
addProperty(args, "GLOBUS_HOSTNAME");
addProperty(args, "GLOBUS_TCP_PORT_RANGE");
@@ -237,7 +233,7 @@
args.add("-Djava.security.egd=file:///dev/urandom");
}
- private void addProperty(List args, String name) {
+ private void addProperty(List<String> args, String name) {
String value = System.getProperty(name);
if (value != null && !value.equals("")) {
args.add("-D" + name + "=" + value);
@@ -266,14 +262,14 @@
URL[] urls = new URL[list.size()];
for (int i = 0; i < list.size(); i++) {
urls[i] = new URL("file://" + CACHE_DIR.getAbsolutePath() + "/"
- + buildName((String[]) list.get(i)));
+ + buildName(list.get(i)));
System.err.println(urls[i]);
}
ClassLoader cl = new URLClassLoader(urls, Bootstrap.class
.getClassLoader());
- Class cls = cl.loadClass(SERVICE_CLASS);
+ Class<?> cls = cl.loadClass(SERVICE_CLASS);
- Method m = cls.getMethod("main", new Class[] { String[].class });
+ Method m = cls.getMethod("main", new Class<?>[] { String[].class });
m.invoke(null, new Object[] { new String[] { registrationURL,
serviceId } });
}
Index: modules/provider-coaster/resources/worker.pl
===================================================================
--- modules/provider-coaster/resources/worker.pl (revision 3354)
+++ modules/provider-coaster/resources/worker.pl (working copy)
@@ -15,6 +15,7 @@
use File::Path;
use File::Copy;
use Getopt::Std;
+use FileHandle;
use Cwd;
use POSIX ":sys_wait_h";
use strict;
@@ -63,6 +64,14 @@
YIELD => 1,
};
+use constant {
+ PUT_START => 0,
+ PUT_CMD_SENT => 1,
+ PUT_SIZE_SENT => 2,
+ PUT_LNAME_SENT => 3,
+ PUT_SENDING_DATA => 4,
+};
+
my $LOGLEVEL = NONE;
my @LEVELS = ("TRACE", "DEBUG", "INFO ", "WARN ", "ERROR");
@@ -80,7 +89,8 @@
REPLY_FLAG => 0x00000001,
FINAL_FLAG => 0x00000002,
ERROR_FLAG => 0x00000004,
- PROGRESSIVE_FLAG => 0x00000008
+ PROGRESSIVE_FLAG => 0x00000008,
+ SIGNAL_FLAG => 0x00000010,
};
use constant {
@@ -91,12 +101,13 @@
STAGEOUT => 0x11,
};
-my $TAG = 0;
+my $TAG = int(rand(10000));
use constant RETRIES => 3;
use constant REPLYTIMEOUT => 180;
use constant MAXFRAGS => 16;
# TODO: Make this configurable (#537)
use constant MAX_RECONNECT_ATTEMPTS => 3;
+use constant NEVER => 9999999999;
use constant JOB_CHECK_SKIP => 32;
@@ -165,6 +176,55 @@
# REPLIES stores the state of (outgoing) commands for which replies are expected
my %REPLIES = ();
+my %SUSPENDED_TRANSFERS = ();
+
+# the structure of the above maps is (fields marked with "*" are optional):
+# tag: [state, time]
+#
+# state: {} - valid keys:
+# tag: the current command/request tag
+# dataIn: proc(state, tag, timeout, err, fin, msg) - invoked when data is received
+# nextData: proc(state) - invoked to get the next data chunk
+# returns: (flags, data, yieldFlag), where
+# flags: the protocol flags to send (e.g. err, fin)
+# data: the actual data
+# yieldFlag: if CONTINUE then it instructs the sending procedure
+# to loop sending data until YIELD is returned
+#
+# dataSent: proc(state, tag) - invoked when all data was sent
+# PUT file specific state:
+# state: a numeric state number:
+# 0 - new request
+# 1 - command sent
+# 2 - file size sent
+# 3 - local name sent (i.e. sending data)
+# size: file size
+# lname: local file name
+# rname: remote file name
+# sent: total bytes sent from this file
+# bindex: block index - multiple I/O buffer size worth of data are sent
+# before yielding to other commands/requests (up to IOBLOCKSZ).
+# This number counts how many buffer sizes in the current block have
+# been sent so far.
+# handle: file handle
+#
+# GET file specific state:
+# state:
+# 0 - new request
+# 1 - size received
+# handle: file handle
+# size: file size
+# lname: local file name
+#
+# state when sending array data:
+# index: the current index in the data array
+# data: an array containing the data chunks
+#
+#
+#
+# time: last communication time (used to determine timeouts)
+#
+
my $LOG = logfilename($LOGDIR, $BLOCKID);
my %HANDLERS = (
@@ -246,11 +306,10 @@
}
sub timestring() {
- # TODO: Make this choice configurable (#541)
- my $t = sprintf("%.3f", time());
- # my @d = localtime(time());
- # my $t = sprintf("%i/%02i/%02i %02i:%02i",
- # $d[5]+1900, $d[4]+1, $d[3], $d[2], $d[1]);
+ #my $t = sprintf("%.3f", time());
+ my $now = time();
+ my @d = localtime($now);
+ my $t = sprintf("%i/%02i/%02i %02i:%02i:%02i.%03i", $d[5]+1900, $d[4]+1, $d[3], $d[2], $d[1], $d[0], ($now*1000) % 1000);
return $t;
}
@@ -333,9 +392,7 @@
print "LOG: $LOG\n";
}
open(LOG, ">>$LOG") or die "Failed to open log file ($LOG): $!";
- my $b = select(LOG);
- $| = 1;
- select($b);
+ LOG->autoflush(1);
my $date = localtime;
wlog INFO, "$BLOCKID Logging started: $date\n";
}
@@ -383,7 +440,7 @@
sub sendm {
my ($tag, $flags, $msg) = @_;
my $len = length($msg);
- my $buf = pack("VVV", $tag, $flags, $len);
+ my $buf = pack("VVVVV", $tag, $flags, $len, ($tag ^ $flags ^ $len), 0);
$buf = $buf.$msg;
wlog(DEBUG, "OUT: len=$len, tag=$tag, flags=$flags\n");
@@ -401,24 +458,28 @@
my $flg2;
my $msg;
my $yield;
- if (defined($$data{"tag"})) {
- $tag = $$data{"tag"};
- }
+
do {
($flg2, $msg, $yield) = $$data{"nextData"}($data);
- sendm($tag, $flg | $flg2, $msg);
+ if (defined($msg)) {
+ sendm($tag, $flg | $flg2, $msg);
+ }
} while (($flg2 & FINAL_FLAG) == 0 && !$yield);
if (($flg2 & FINAL_FLAG) == 0) {
# final flag not set; put it back in the queue
- wlog DEBUG, "$tag yielding\n";
- $$data{"tag"} = $tag;
+ wlog TRACE, "$tag yielding\n";
+
+ # update last time
+ my $record = $REPLIES{$tag};
+ $$record[1] = time();
+
queueCmdCustomDataHandling($REPLIES{$tag}, $data);
}
else {
if (exists($REPLIES{$tag})) {
my $record = $REPLIES{$tag};
- my ($cont, $start) = ($$record[0], $$record[1]);
+ my ($cont, $lastTime) = ($$record[0], $$record[1]);
if (defined($$cont{"dataSent"})) {
$$cont{"dataSent"}($cont, $tag);
}
@@ -451,38 +512,48 @@
my ($state) = @_;
my $s = $$state{"state"};
- if ($s == 0) {
+
+ my $tag = $$state{"tag"};
+
+ wlog TRACE, "$tag nextFileData state=$s\n";
+
+ if ($s == PUT_START) {
$$state{"state"} = $s + 1;
return (0, $$state{"cmd"}, CONTINUE);
}
- elsif ($s == 1) {
+ elsif ($s == PUT_CMD_SENT) {
$$state{"state"} = $s + 1;
return (0, pack("VV", $$state{"size"}, 0), CONTINUE);
}
- elsif ($s == 2) {
+ elsif ($s == PUT_SIZE_SENT) {
$$state{"state"} = $s + 1;
return (0, $$state{"lname"}, CONTINUE);
}
- elsif ($s == 3) {
+ elsif ($s == PUT_LNAME_SENT) {
$$state{"state"} = $s + 1;
$$state{"sent"} = 0;
$$state{"bindex"} = 0;
return ($$state{"size"} == 0 ? FINAL_FLAG : 0, $$state{"rname"}, CONTINUE);
}
- else {
+ elsif ($s == PUT_SENDING_DATA) {
+ if (defined $SUSPENDED_TRANSFERS{"$tag"}) {
+ wlog TRACE, "$tag Transfer suspendend; yielding\n";
+ return (0, undef, YIELD);
+ }
+
my $handle = $$state{"handle"};
my $buffer;
my $sz = read($handle, $buffer, IOBUFSZ);
if (!defined $sz) {
- wlog INFO, "Failed to read data from file: $!\n";
+ wlog INFO, "$tag Failed to read data from file: $!\n";
return (FINAL_FLAG + ERROR_FLAG, "$!", CONTINUE);
}
elsif ($sz == 0 && $$state{"sent"} < $$state{"size"}) {
- wlog INFO, "File size mismatch. $$state{'size'} vs. $$state{'sent'}\n";
+ wlog INFO, "$tag File size mismatch. $$state{'size'} vs. $$state{'sent'}\n";
return (FINAL_FLAG + ERROR_FLAG, "File size mismatch. Expected $$state{'size'}, got $$state{'sent'}", CONTINUE);
}
$$state{"sent"} += $sz;
- wlog DEBUG, "size: $$state{'size'}, sent: $$state{'sent'}\n";
+ wlog DEBUG, "$tag size: $$state{'size'}, sent: $$state{'sent'}\n";
if ($$state{"sent"} == $$state{"size"}) {
close $handle;
}
@@ -523,6 +594,8 @@
if (!defined $ctag) {
$ctag = $TAG++;
registerCmd($ctag, $cont);
+ # make the tag accessible to the data generator
+ $$state{"tag"} = $ctag;
}
sendFrags($ctag, 0, $state);
return $ctag;
@@ -537,6 +610,7 @@
sub queueCmd {
my @cmd = @_;
my $cont = shift(@cmd);
+ # $cont is the continuation (what gets called when a reply is received)
push @CMDQ, [$cont, arrayData(@cmd)];
}
@@ -559,13 +633,23 @@
my ($data) = @_;
my $lendata = length($data);
- if ($lendata < 12) {
- wlog WARN, "Received faulty message (length < 12: $lendata)\n";
- die "Received faulty message (length < 12: $lendata)";
+ if ($lendata < 20) {
+ wlog WARN, "Received faulty message (length < 20: $lendata)\n";
+ die "Received faulty message (length < 20: $lendata)";
}
my $tag = unpack("V", substr($data, 0, 4));
my $flg = unpack("V", substr($data, 4, 4));
my $len = unpack("V", substr($data, 8, 4));
+ my $hcsum = unpack("V", substr($data, 12, 4));
+ my $csum = unpack("V", substr($data, 16, 4));
+
+ my $chcsum = ($tag ^ $flg ^ $len);
+
+ if ($chcsum != $hcsum) {
+ wlog WARN, "Header checksum failed. Computed checksum: $chcsum, checksum: $hcsum\n";
+ return;
+ }
+
my $msg;
my $frag;
my $alen = 0;
@@ -574,7 +658,7 @@
$alen = $alen + length($frag);
$msg = $msg.$frag;
}
-
+
my $actuallen = length($msg);
wlog(TRACE, " IN: len=$len, actuallen=$actuallen, tag=$tag, flags=$flg, $msg\n");
if ($len != $actuallen) {
@@ -584,7 +668,7 @@
}
sub processRequest {
- my ($state, $tag, $timeout, $err, $fin, $msg) = @_;
+ my ($state, $tag, $timeout, $flags, $msg) = @_;
my $request = $$state{"request"};
if (!defined($request)) {
@@ -596,7 +680,7 @@
if ($timeout) {
sendError($tag, ("Timed out waiting for all fragments"));
}
- elsif (!$fin) {
+ elsif (!($flags & FINAL_FLAG)) {
return;
}
else {
@@ -617,15 +701,17 @@
my $reply = $flg & REPLY_FLAG;
- my ($record, $cont, $start);
+ my ($record, $cont, $lastTime);
if ($reply) {
if (exists($REPLIES{$tag})) {
$record = $REPLIES{$tag};
- ($cont, $start) = ($$record[0], $$record[1]);
+ ($cont, $lastTime) = ($$record[0], $$record[1]);
+ # update last time
+ $$record[1] = time();
}
else {
- wlog(WARN, "received reply to unregistered command (tag=$tag). Discarding.\n");
+ wlog(WARN, "received reply to unregistered command (tag=$tag, msg=$msg). Discarding.\n");
return;
}
}
@@ -635,7 +721,7 @@
wlog DEBUG, "New request ($tag)\n";
}
$record = $REQUESTS{$tag};
- ($cont, $start) = ($$record[0], $$record[1]);
+ ($cont, $lastTime) = ($$record[0], $$record[1]);
}
my $fin = $flg & FINAL_FLAG;
@@ -658,7 +744,7 @@
wlog DEBUG, "Fin flag set\n";
}
- $$cont{"dataIn"}($cont, $tag, 0, $err, $fin, $msg);
+ $$cont{"dataIn"}($cont, $tag, 0, $flg, $msg);
return 1;
}
@@ -702,10 +788,10 @@
sub recvOne {
my $buf;
$SOCK->blocking(0);
- $SOCK->recv($buf, 12 - length($DATA));
+ $SOCK->recv($buf, 20 - length($DATA));
if (length($buf) > 0) {
$DATA = $DATA . $buf;
- if (length($DATA) == 12) {
+ if (length($DATA) == 20) {
# wlog DEBUG, "Received " . unpackData($DATA) . "\n";
eval { process(unpackData($DATA)); } || (wlog ERROR, "Failed to process data: $@\n" && die "Failed to process data: $@");
$DATA = "";
@@ -744,7 +830,7 @@
# things may be added to it while stuff is being sent
my $sz = scalar(@CMDQ);
for (my $i = 0; $i < $sz; $i++) {
- $cmd = pop(@CMDQ);
+ $cmd = shift(@CMDQ);
sendCmdInt(@$cmd);
}
checkJobs();
@@ -774,12 +860,12 @@
}
sub registerCBDataIn {
- my ($state, $tag, $timeout, $err, $fin, $reply) = @_;
+ my ($state, $tag, $timeout, $flags, $reply) = @_;
if ($timeout) {
die "Failed to register (timeout)\n";
}
- elsif ($err) {
+ elsif ($flags & ERROR_FLAG) {
die "Failed to register (service returned error: ".join("\n", $reply).")";
}
else {
@@ -795,7 +881,7 @@
}
sub heartbeatCBDataIn {
- my ($state, $tag, $timeout, $err, $fin, $reply) = @_;
+ my ($state, $tag, $timeout, $flags, $reply) = @_;
if ($timeout) {
if (time() - $LAST_HEARTBEAT > 2 * HEARTBEAT_INTERVAL) {
@@ -803,7 +889,7 @@
die "Lost heartbeat\n";
}
}
- elsif ($err) {
+ elsif ($flags & ERROR_FLAG) {
wlog WARN, "Heartbeat failed: $reply\n";
die "Heartbeat failed: $reply\n";
}
@@ -851,7 +937,8 @@
sub heartbeat {
my ($tag, $timeout, $msgs) = @_;
$LAST_HEARTBEAT = time();
- sendReply($tag, ("OK"));
+ my $msg = int(time() * 1000);
+ sendReply($tag, ("$msg"));
}
sub workershellcmd {
@@ -928,8 +1015,8 @@
mkfdir($jobid, $dst);
# don't try open(DESC, ...) (as I did). It will use the same reference
# and concurrent operations will fail.
- my $desc;
- if (!open($desc, ">", "$dst")) {
+ my $handle;
+ if (!open($handle, ">", "$dst")) {
die "Failed to open $dst: $!";
}
else {
@@ -939,7 +1026,7 @@
"dataIn" => \&getFileCBDataIn,
"state" => 0,
"lfile" => $dst,
- "desc" => $desc
+ "handle" => $handle
};
}
}
@@ -953,11 +1040,12 @@
}
sub getFileCBDataInIndirect {
- my ($state, $tag, $timeout, $err, $fin, $reply) = @_;
+ my ($state, $tag, $timeout, $flags, $reply) = @_;
my $jobid = $$state{"jobid"};
- wlog DEBUG, "$jobid getFileCBDataInIndirect jobid: $jobid, tag: $tag, err: $err, fin: $fin\n";
- if ($err) {
+ wlog DEBUG, "$jobid getFileCBDataInIndirect jobid: $jobid, tag: $tag, flags: $flags\n";
+ if ($flags & ERROR_FLAG) {
+ wlog DEBUG, "$jobid getFileCBDataInIndirect error: $reply\n";
queueCmd((nullCB(), "JOBSTATUS", $jobid, FAILED, "520", "Error staging in file: $reply"));
delete($JOBDATA{$jobid});
return;
@@ -967,19 +1055,28 @@
delete($JOBDATA{$jobid});
return;
}
- if ($fin) {
+ if ($flags & FINAL_FLAG) {
stagein($jobid);
}
}
sub getFileCBDataIn {
- my ($state, $tag, $timeout, $err, $fin, $reply) = @_;
+ my ($state, $tag, $timeout, $flags, $reply) = @_;
my $s = $$state{"state"};
my $jobid = $$state{"jobid"};
- wlog DEBUG, "$jobid getFileCBDataIn jobid: $jobid, state: $s, tag: $tag, err: $err, fin: $fin\n";
- if ($err) {
+ my $len = length($reply);
+ wlog DEBUG, "$jobid getFileCBDataIn jobid: $jobid, state: $s, tag: $tag, flags: $flags, len: $len\n";
+
+ if ($flags & SIGNAL_FLAG) {
+ if ($reply eq "QUEUED") {
+ $REPLIES{$tag}[1] = NEVER;
+ wlog DEBUG, "$jobid transfer queued\n";
+ }
+ return;
+ }
+ elsif ($flags & ERROR_FLAG) {
wlog DEBUG, "$jobid getFileCBDataIn FAILED 520 Error staging in file: $reply\n";
queueCmd((nullCB(), "JOBSTATUS", $jobid, FAILED, "520", "Error staging in file: $reply"));
delete($JOBDATA{$jobid});
@@ -993,21 +1090,22 @@
elsif ($s == 0) {
$$state{"state"} = 1;
$$state{"size"} = unpack("V", $reply);
+ wlog DEBUG, "$tag $jobid got file size: $$state{'size'}\n";
my $lfile = $$state{"lfile"};
}
else {
- my $desc = $$state{"desc"};
- if (!(print {$desc} $reply)) {
- close $desc;
- wlog DEBUG, "$jobid Could not write to file: $!. Descriptor was $desc; lfile: $$state{'lfile'}\n";
+ my $handle = $$state{"handle"};
+ if (!(print {$handle} $reply)) {
+ close $handle;
+ wlog DEBUG, "$jobid Could not write to file: $!. Descriptor was $handle; lfile: $$state{'lfile'}\n";
queueCmd((nullCB(), "JOBSTATUS", $jobid, FAILED, "522", "Could not write to file: $!"));
delete($JOBDATA{$jobid});
return;
}
}
- if ($fin) {
- my $desc = $$state{"desc"};
- close $desc;
+ if ($flags & FINAL_FLAG) {
+ my $handle = $$state{"handle"};
+ close $handle;
wlog DEBUG, "$jobid Closed $$state{'lfile'}\n";
if ($PINNED_READY) {
completePinnedFile($jobid);
@@ -1220,6 +1318,13 @@
wlog DEBUG, "$jobid Staging out $lfile (mode = $mode).\n";
my ($protocol, $host, $path) = urisplit($rfile);
if ($protocol eq "file" || $protocol eq "proxy") {
+ # make sure we keep track of the total number of actual stageouts
+ if (!defined $JOBDATA{$jobid}{"stageoutCount"}) {
+ $JOBDATA{$jobid}{"stageoutCount"} = 0;
+ }
+ $JOBDATA{$jobid}{"stageoutCount"} += 1;
+ wlog DEBUG, "$jobid Stagecount is $JOBDATA{$jobid}{stageoutCount}\n";
+
queueCmdCustomDataHandling(putFileCB($jobid), fileData("PUT", $lfile, $rfile));
}
elsif ($protocol eq "sfs") {
@@ -1254,16 +1359,34 @@
}
}
+sub sendStatus {
+ my ($jobid) = @_;
+
+ my $ec = $JOBDATA{$jobid}{"exitcode"};
+
+ if ($ec == 0) {
+ queueCmd((nullCB(), "JOBSTATUS", $jobid, COMPLETED, "0", ""));
+ }
+ else {
+ queueCmd((nullCB(), "JOBSTATUS", $jobid, FAILED, "$ec", "Job failed with an exit code of $ec"));
+ }
+}
+
sub cleanup {
my ($jobid) = @_;
my $ec = $JOBDATA{$jobid}{"exitcode"};
if (ASYNC) {
- if ($ec == 0) {
- queueCmd((nullCB(), "JOBSTATUS", $jobid, COMPLETED, "0", ""));
+ if (!defined($JOBDATA{$jobid}{"stageoutCount"}) || ($JOBDATA{$jobid}{"stageoutCount"} == 0)) {
+ # there were no stageouts. Notification can be sent now
+ wlog DEBUG, "$jobid There were no stageouts. Sending notification immediately\n";
+ sendStatus($jobid);
}
else {
- queueCmd((nullCB(), "JOBSTATUS", $jobid, FAILED, "$ec", "Job failed with an exit code of $ec"));
+ # there were stageouts. Wait until all are acknowledged
+ # as done by the client. And we keep track of the
+ # count of stageouts that weren't acknowledged in
+ # $JOBDATA{$jobid}{"stageoutCount"}
}
}
@@ -1282,7 +1405,7 @@
chop $c;
}
wlog DEBUG, "$jobid Removing $c\n";
- rmtree($c, {safe => 1, verbose => 0});
+ rmtree($c, 0, 0);
wlog DEBUG, "$jobid Removed $c\n";
}
}
@@ -1311,35 +1434,52 @@
my ($state, $tag) = @_;
if (ASYNC) {
- wlog DEBUG, "putFileCBDataSent\n";
+ wlog DEBUG, "$tag putFileCBDataSent\n";
my $jobid = $$state{"jobid"};
- if ($jobid != -1) {
- wlog DEBUG, "Data sent, async is on. Staging out next file\n";
+ if ($jobid != -1) {
+ wlog DEBUG, "$tag Data sent, async is on. Staging out next file\n";
stageout($jobid);
}
}
}
sub putFileCBDataIn {
- my ($state, $tag, $timeout, $err, $fin, $reply) = @_;
+ my ($state, $tag, $timeout, $flags, $reply) = @_;
- wlog DEBUG, "putFileCBDataIn: $reply\n";
+ wlog DEBUG, "$tag putFileCBDataIn msg=$reply\n";
my $jobid = $$state{"jobid"};
- if ($err || $timeout) {
+ if (($flags & ERROR_FLAG) || $timeout) {
if ($JOBDATA{$jobid}) {
- wlog DEBUG, "Stage out failed ($reply)\n";
+ wlog DEBUG, "$tag Stage out failed ($reply)\n";
queueCmd((nullCB(), "JOBSTATUS", $jobid, FAILED, "515", "Stage out failed ($reply)"));
delete($JOBDATA{$jobid});
}
return;
}
+ elsif ($reply eq "STOP") {
+ $SUSPENDED_TRANSFERS{"$tag"} = 1;
+ wlog DEBUG, "$tag Got stop request. Suspending transfer.\n";
+ }
+ elsif ($reply eq "CONTINUE") {
+ delete $SUSPENDED_TRANSFERS{"$tag"};
+ wlog DEBUG, "$tag Got continue request. Resuming transfer.\n";
+ }
elsif ($jobid != -1) {
+ # OK reply from client
if (!ASYNC) {
- wlog DEBUG, "Stageout done; staging out next file\n";
+ wlog DEBUG, "$tag Stageout done; staging out next file\n";
stageout($jobid);
}
+ else {
+ wlog DEBUG, "$jobid Stageout done; stagecount is $JOBDATA{$jobid}{stageoutCount}\n";
+ $JOBDATA{$jobid}{"stageoutCount"} -= 1;
+ if ($JOBDATA{$jobid}{"stageoutCount"} == 0) {
+ wlog DEBUG, "$jobid All stageouts acknowledged. Sending notification\n";
+ sendStatus($jobid);
+ }
+ }
}
}
@@ -1492,21 +1632,24 @@
}
$JOBDATA{$JOBID}{"jobslot"} = $JOBSLOT;
- pipe(PARENT_R, CHILD_W);
+ my ($PARENT_R, $CHILD_W);
+ pipe($PARENT_R, $CHILD_W);
+
$pid = fork();
+
if (defined($pid)) {
if ($pid == 0) {
- close PARENT_R;
- runjob(\*CHILD_W, $JOB, $JOBARGS, $JOBENV, $JOBSLOT, $WORKERPID);
- close CHILD_W;
+ close $PARENT_R;
+ runjob($CHILD_W, $JOB, $JOBARGS, $JOBENV, $JOBSLOT, $WORKERPID);
+ close $CHILD_W;
}
else {
wlog DEBUG, "$JOBID Forked process $pid. Waiting for its completion\n";
- close CHILD_W;
+ close $CHILD_W;
$JOBS_RUNNING++;
$JOBWAITDATA{$JOBID} = {
pid => $pid,
- pipe => \*PARENT_R
+ pipe => $PARENT_R
};
if ($PROFILE) {
push(@PROFILE_EVENTS, "FORK", $pid, time());
Index: modules/provider-coaster/resources/log4j.properties
===================================================================
--- modules/provider-coaster/resources/log4j.properties (revision 3354)
+++ modules/provider-coaster/resources/log4j.properties (working copy)
@@ -27,3 +27,5 @@
#log4j.logger.org.globus.cog.karajan.workflow.service.channels.AbstractKarajanChannel=WARN
log4j.logger.org.globus.cog.abstraction.coaster=INFO
log4j.logger.org.globus.cog.abstraction.impl.common.task.TaskImpl=DEBUG
+log4j.logger.org.globus.cog.karajan.workflow.service.channels.PerformanceDiagnosticInputStream=INFO
+log4j.logger.org.globus.cog.karajan.workflow.service.channels.PerformanceDiagnosticOutputStream=INFO
Index: modules/abstraction-common/.classpath
===================================================================
--- modules/abstraction-common/.classpath (revision 3354)
+++ modules/abstraction-common/.classpath (working copy)
@@ -6,7 +6,6 @@
<classpathentry kind="lib" path="lib/castor-0.9.6.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/util"/>
<classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry exported="true" kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j-1.2.8"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry exported="true" kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/file/FileFragmentImpl.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/file/FileFragmentImpl.java (revision 3354)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/file/FileFragmentImpl.java (working copy)
@@ -17,10 +17,17 @@
public FileFragmentImpl(String file, long offset, long length) {
this.file = file;
- this.offset = offset;
- this.length = length;
+ this.offset = checkPositive(offset, "offset");
+ this.length = checkPositive(length, "length");
}
+ private long checkPositive(long n, String param) {
+ if (n < 0) {
+ throw new IllegalArgumentException(param + " < 0 (" + n + ")");
+ }
+ return n;
+ }
+
/**
* Creates a new FileFragment object for the entire specified file
*/
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/file/AbstractFileResource.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/file/AbstractFileResource.java (revision 3354)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/file/AbstractFileResource.java (working copy)
@@ -135,37 +135,31 @@
return this.attributes.get(name);
}
- @Override
public void getFile(String remoteFileName, String localFileName)
throws FileResourceException {
getFile(new FileFragmentImpl(remoteFileName), new FileFragmentImpl(localFileName));
}
- @Override
public void getFile(String remoteFileName, String localFileName,
ProgressMonitor progressMonitor) throws FileResourceException {
getFile(new FileFragmentImpl(remoteFileName), new FileFragmentImpl(localFileName), progressMonitor);
}
- @Override
public void getFile(FileFragment remote, FileFragment local)
throws FileResourceException {
getFile(remote, local, null);
}
- @Override
public void putFile(String localFileName, String remoteFileName)
throws FileResourceException {
putFile(new FileFragmentImpl(localFileName), new FileFragmentImpl(remoteFileName));
}
- @Override
public void putFile(String localFileName, String remoteFileName,
ProgressMonitor progressMonitor) throws FileResourceException {
putFile(new FileFragmentImpl(localFileName), new FileFragmentImpl(remoteFileName), progressMonitor);
}
- @Override
public void putFile(FileFragment local, FileFragment remote)
throws FileResourceException {
putFile(local, remote, null);
@@ -386,7 +380,6 @@
return "FileResource: " + name;
}
- @Override
public void thirdPartyTransfer(FileResource sourceResource,
FileFragment source, FileFragment destination)
throws FileResourceException {
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/TaskImpl.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/TaskImpl.java (revision 3354)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/TaskImpl.java (working copy)
@@ -183,7 +183,7 @@
}
}
finally {
- outputListeners.release();
+ outputListeners.release(i);
}
}
@@ -241,7 +241,7 @@
}
}
finally {
- statusListeners.release();
+ statusListeners.release(i);
}
synchronized (this) {
if (anythingWaiting) {
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/JobSpecificationImpl.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/JobSpecificationImpl.java (revision 3354)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/task/JobSpecificationImpl.java (working copy)
@@ -166,7 +166,6 @@
}
- @Override
public void addEnvironmentVariable(String name, int i) {
addEnvironmentVariable(name, Integer.toString(i));
}
@@ -469,7 +468,6 @@
return result;
}
- @Override
public void unpackProviderAttributes() {
String attrs = (String) getAttribute("providerAttributes");
Index: modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/execution/WallTime.java
===================================================================
--- modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/execution/WallTime.java (revision 3354)
+++ modules/abstraction-common/src/org/globus/cog/abstraction/impl/common/execution/WallTime.java (working copy)
@@ -12,15 +12,16 @@
import java.util.HashMap;
import java.util.Map;
-public class WallTime implements Comparable {
- private static final Map FORMATTERS;
+public class WallTime implements Comparable<WallTime> {
+ private static final Map<String, Formatter> FORMATTERS;
private static final Formatter DEFAULT_FORMATTER = new DefaultFormatter();
static {
- FORMATTERS = new HashMap();
+ FORMATTERS = new HashMap<String, Formatter>();
FORMATTERS.put(null, DEFAULT_FORMATTER);
FORMATTERS.put("default", DEFAULT_FORMATTER);
FORMATTERS.put("pbs", new PBSFormatter());
+ FORMATTERS.put("hms", new HHMMSSFormatter());
FORMATTERS.put("globus-jobmanager-pbs", new PBSFormatter());
FORMATTERS.put("pbs-native", new NativePBSFormatter());
FORMATTERS.put("sge-native", new NativeSGEFormatter());
@@ -30,7 +31,7 @@
if (type != null) {
type = type.toLowerCase();
}
- Formatter f = (Formatter) FORMATTERS.get(type);
+ Formatter f = FORMATTERS.get(type);
return f == null ? DEFAULT_FORMATTER : f;
}
@@ -74,11 +75,11 @@
return seconds;
}
- public static String format(String type, int seconds) {
+ public static String format(String type, long seconds) {
return getFormatter(type).format(seconds);
}
- public static String format(int seconds) {
+ public static String format(long seconds) {
return format(null, seconds);
}
@@ -86,7 +87,7 @@
return format(target, timeToSeconds(spec));
}
- private static void pad(StringBuffer sb, int value) {
+ private static void pad(StringBuffer sb, long value) {
if (value < 10) {
sb.append('0');
}
@@ -128,30 +129,30 @@
}
public static interface Formatter {
- String format(int seconds);
+ String format(long seconds);
}
private static class DefaultFormatter implements Formatter {
- public String format(int seconds) {
- return String.valueOf((int) Math.ceil((double) seconds / 60));
+ public String format(long seconds) {
+ return String.valueOf((long) Math.ceil((double) seconds / 60));
}
}
private static class HHMMSSFormatter implements Formatter {
- private static int seconds(int secondsInterval) {
+ private static long seconds(long secondsInterval) {
return secondsInterval % 60;
}
- private static int minutes(int secondsInterval) {
+ private static long minutes(long secondsInterval) {
return (secondsInterval / 60) % 60;
}
- private static int hours(int secondsInterval) {
+ private static long hours(long secondsInterval) {
return secondsInterval / 3600;
}
- public String format(int seconds) {
+ public String format(long seconds) {
StringBuffer sb = new StringBuffer();
pad(sb, hours(seconds));
sb.append(':');
@@ -177,12 +178,7 @@
private static class NativeSGEFormatter extends HHMMSSFormatter {
}
- public int compareTo(Object o) {
- if (o instanceof WallTime) {
- return seconds - ((WallTime) o).seconds;
- }
- else {
- throw new ClassCastException(o.getClass().getName());
- }
+ public int compareTo(WallTime o) {
+ return seconds - o.seconds;
}
}
Index: modules/provider-dcache/.classpath
===================================================================
--- modules/provider-dcache/.classpath (revision 3354)
+++ modules/provider-dcache/.classpath (working copy)
@@ -4,6 +4,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/abstraction-common"/>
<classpathentry combineaccessrules="false" kind="src" path="/abstraction-provider-local"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
- <classpathentry kind="output" path="bin"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
+ <classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-webdav/.classpath
===================================================================
--- modules/provider-webdav/.classpath (revision 3354)
+++ modules/provider-webdav/.classpath (working copy)
@@ -11,6 +11,6 @@
<accessrule kind="nonaccessible" pattern="**/CVS/*"/>
</accessrules>
</classpathentry>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/provider-webdav/src/org/globus/cog/abstraction/impl/file/http/FileResourceImpl.java
===================================================================
--- modules/provider-webdav/src/org/globus/cog/abstraction/impl/file/http/FileResourceImpl.java (revision 3354)
+++ modules/provider-webdav/src/org/globus/cog/abstraction/impl/file/http/FileResourceImpl.java (working copy)
@@ -229,12 +229,10 @@
throw new UnsupportedOperationException("submit");
}
- @Override
public boolean supportsPartialTransfers() {
return false;
}
- @Override
public boolean supportsThirdPartyTransfers() {
return false;
}
Index: modules/provider-webdav/src/org/globus/cog/abstraction/impl/file/webdav/FileResourceImpl.java
===================================================================
--- modules/provider-webdav/src/org/globus/cog/abstraction/impl/file/webdav/FileResourceImpl.java (revision 3354)
+++ modules/provider-webdav/src/org/globus/cog/abstraction/impl/file/webdav/FileResourceImpl.java (working copy)
@@ -330,12 +330,10 @@
tempFile.delete();
}
- @Override
public boolean supportsPartialTransfers() {
return false;
}
- @Override
public boolean supportsThirdPartyTransfers() {
return false;
}
Index: modules/karajan/src/org/globus/cog/karajan/arguments/NamedArgumentsImpl.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/arguments/NamedArgumentsImpl.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/arguments/NamedArgumentsImpl.java (working copy)
@@ -70,7 +70,7 @@
}
}
- public void addInitial(String name, Object value) {
+ public synchronized void addInitial(String name, Object value) {
named.put(name, value);
}
@@ -105,7 +105,7 @@
return named.keySet().iterator();
}
- public Object getArgument(String name) {
+ public synchronized Object getArgument(String name) {
if (named != null) {
return named.get(name);
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/TimeoutException.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/TimeoutException.java (revision 0)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/TimeoutException.java (revision 3355)
@@ -0,0 +1,30 @@
+//----------------------------------------------------------------------
+//This code is developed as part of the Java CoG Kit project
+//The terms of the license can be found at http://www.cogkit.org/license
+//This message may not be removed or altered.
+//----------------------------------------------------------------------
+
+/*
+ * Created on Aug 2, 2005
+ */
+package org.globus.cog.karajan.workflow.service;
+
+public class TimeoutException extends ProtocolException {
+ private static final long serialVersionUID = -6781619140427115780L;
+
+ public TimeoutException() {
+ super();
+ }
+
+ public TimeoutException(String message) {
+ super(message);
+ }
+
+ public TimeoutException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public TimeoutException(Throwable cause) {
+ super(cause);
+ }
+}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/RequestReply.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/RequestReply.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/RequestReply.java (working copy)
@@ -15,6 +15,8 @@
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
@@ -25,11 +27,16 @@
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
+import org.apache.log4j.Logger;
import org.globus.cog.karajan.util.serialization.XMLConverter;
import org.globus.cog.karajan.workflow.service.channels.AbstractKarajanChannel;
import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
public abstract class RequestReply {
+ public static final Logger logger = Logger.getLogger(RequestReply.class);
+
+ public static final int DEFAULT_TIMEOUT = 120 * 1000;
+ private int timeout = DEFAULT_TIMEOUT;
public static final int NOID = -1;
private int id;
@@ -39,6 +46,9 @@
private List<byte[]> inData;
private boolean inDataReceived;
private KarajanChannel channel;
+ private long lastTime = Long.MAX_VALUE;
+
+ public static final DateFormat DF = new SimpleDateFormat("yyMMdd-HHmmss.SSS");
// private static final byte[] NO_EXCEPTION = new byte[0];
@@ -57,8 +67,7 @@
protected void setOutCmd(String outCmd) {
this.outCmd = outCmd;
}
-
- @SuppressWarnings("hiding")
+
public void register(KarajanChannel channel) {
this.channel = channel;
}
@@ -132,12 +141,11 @@
}
public abstract void send(boolean err) throws ProtocolException;
-
- @SuppressWarnings("unused")
+
protected void dataReceived(boolean fin, boolean error, byte[] data) throws ProtocolException {
+ setLastTime(System.currentTimeMillis());
}
-
- @SuppressWarnings("unused")
+
protected synchronized void addInData(boolean fin, boolean err, byte[] data) {
if (inData == null) {
inData = new ArrayList<byte[]>(4);
@@ -145,7 +153,6 @@
inData.add(data);
}
- @SuppressWarnings("unused")
protected final void addInData(byte[] data) {
throw new RuntimeException("Should not be used");
}
@@ -345,4 +352,29 @@
protected Object getInObject(int index) {
return deserialize(getInData(index));
}
+
+ public long getLastTime() {
+ return lastTime;
+ }
+
+ public void setLastTime(long lastTime) {
+ this.lastTime = lastTime;
+ }
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ public void handleTimeout() {
+ logger.warn("Unhandled timeout", new Throwable());
+ setLastTime(Long.MAX_VALUE);
+ }
+
+ public void handleSignal(byte[] data) {
+
+ }
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/PerformanceDiagnosticOutputStream.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/PerformanceDiagnosticOutputStream.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/PerformanceDiagnosticOutputStream.java (working copy)
@@ -27,13 +27,12 @@
public void run() {
count++;
String s;
- logger.info(s = "Total transferred: "
+ logger.info(s = "[OUT] Total transferred: "
+ PerformanceDiagnosticInputStream.units(bytes) + "B, current rate: "
+ PerformanceDiagnosticInputStream.units(bytes - last)
+ "B/s, average rate: "
+ PerformanceDiagnosticInputStream.units(bytes / count)
+ "B/s");
- System.out.println("[OUT] " + s);
last = bytes;
}
});
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/ChannelContext.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/ChannelContext.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/ChannelContext.java (working copy)
@@ -9,6 +9,8 @@
*/
package org.globus.cog.karajan.workflow.service.channels;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
@@ -38,8 +40,8 @@
private String remoteContact;
private UserContext userContext;
private int cmdseq;
- private TagTable activeSenders;
- private TagTable activeReceivers;
+ private TagTable<Command> activeSenders;
+ private TagTable<RequestHandler> activeReceivers;
// private Map reexecutionSet;
private static Timer timer;
private ServiceContext serviceContext;
@@ -55,9 +57,9 @@
public ChannelContext(ServiceContext sc) {
attributes = new HashMap<String,Object>();
- activeSenders = new TagTable();
- activeReceivers = new TagTable();
- // reexecutionSet = new Hashtable();
+ activeSenders = new TagTable<Command>();
+ activeReceivers = new TagTable<RequestHandler>();
+
channelID = new ChannelID();
this.serviceContext = sc;
}
@@ -74,7 +76,7 @@
public synchronized void setUserContext(UserContext userContext) {
this.userContext = userContext;
}
-
+
public synchronized UserContext newUserContext(String name) throws ChannelException {
if (userContext != null && userContext.getName() != null) {
try {
@@ -140,7 +142,7 @@
return channelID;
}
- public int nextCmdSeq() {
+ public synchronized int nextCmdSeq() {
cmdseq = cmdseq + 1;
while (activeSenders.containsKey(cmdseq) || activeReceivers.containsKey(cmdseq)) {
cmdseq = cmdseq + 1;
@@ -148,19 +150,39 @@
return cmdseq;
}
- public synchronized void registerCommand(Command cmd) throws ProtocolException {
+ public void registerCommand(Command cmd) throws ProtocolException {
if (cmd.getId() == RequestReply.NOID) {
cmd.setId(nextCmdSeq());
- activeSenders.put(cmd.getId(), cmd);
+ synchronized(activeSenders) {
+ activeSenders.put(cmd.getId(), cmd);
+ }
}
else {
throw new ProtocolException("Command already registered with id " + cmd.getId());
}
}
+
+ public Collection<Command> getActiveCommands() {
+ List<Command> l = new ArrayList<Command>();
+ synchronized(activeSenders) {
+ l.addAll(activeSenders.values());
+ }
+ return l;
+ }
+
+ public Collection<RequestHandler> getActiveHandlers() {
+ List<RequestHandler> l = new ArrayList<RequestHandler>();
+ synchronized(activeReceivers) {
+ l.addAll(activeReceivers.values());
+ }
+ return l;
+ }
public void unregisterCommand(Command cmd) {
Object removed;
- removed = activeSenders.remove(cmd.getId());
+ synchronized(activeSenders) {
+ removed = activeSenders.remove(cmd.getId());
+ }
if (removed == null) {
logger.warn("Attempted to unregister unregistered command with id " + cmd.getId());
}
@@ -170,23 +192,31 @@
}
public void registerHandler(RequestHandler handler, int tag) {
- activeReceivers.put(tag, handler);
+ synchronized(activeReceivers) {
+ activeReceivers.put(tag, handler);
+ }
}
public void unregisterHandler(int tag) {
Object removed;
- removed = activeReceivers.remove(tag);
+ synchronized(activeReceivers) {
+ removed = activeReceivers.remove(tag);
+ }
if (removed == null) {
logger.warn("Attempted to unregister unregistered handler with id " + tag);
}
}
public Command getRegisteredCommand(int id) {
- return (Command) activeSenders.get(id);
+ synchronized(activeSenders) {
+ return activeSenders.get(id);
+ }
}
public RequestHandler getRegisteredHandler(int id) {
- return (RequestHandler) activeReceivers.get(id);
+ synchronized(activeReceivers) {
+ return activeReceivers.get(id);
+ }
}
public void notifyRegisteredListeners(Exception e) {
@@ -195,8 +225,10 @@
}
private void notifyListeners(TagTable map, Exception t) {
- for (Object o : map.values())
- ((RequestReply) o).errorReceived(null, t);
+ synchronized(map) {
+ for (Object o : map.values())
+ ((RequestReply) o).errorReceived(null, t);
+ }
}
public Timer getTimer() {
@@ -235,6 +267,12 @@
attributes.put(name, o);
}
}
+
+ public Object getAttribute(String name) {
+ synchronized(attributes) {
+ return attributes.get(name);
+ }
+ }
public int getReconnectionAttempts() {
return reconnectionAttempts;
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractPipedChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractPipedChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractPipedChannel.java (working copy)
@@ -9,14 +9,14 @@
*/
package org.globus.cog.karajan.workflow.service.channels;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
import org.apache.log4j.Logger;
+import org.globus.cog.karajan.workflow.service.RemoteConfiguration.Entry;
import org.globus.cog.karajan.workflow.service.RequestManager;
import org.globus.cog.karajan.workflow.service.UserContext;
-import org.globus.cog.karajan.workflow.service.RemoteConfiguration.Entry;
-import edu.emory.mathcs.backport.java.util.concurrent.BlockingQueue;
-import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
-
/**
* A channel implementation for which the other endpoint lives in the
* same JVM.
@@ -75,10 +75,10 @@
byte[] copy = new byte[bytes.length];
System.arraycopy(bytes, 0, copy, 0, bytes.length);
if (reply) {
- s.handleReply(tag, fin, error, copy.length, copy);
+ s.handleReply(tag, flags, copy.length, copy);
}
else {
- s.handleRequest(tag, fin, error, copy.length, copy);
+ s.handleRequest(tag, flags, copy.length, copy);
}
if (cb != null) {
cb.dataSent();
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/TagTable.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/TagTable.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/TagTable.java (working copy)
@@ -13,14 +13,14 @@
import java.util.HashMap;
import java.util.Map;
-public class TagTable {
+public class TagTable<T> {
private static final long serialVersionUID = 1659255187618780167L;
- private Map<MutableInteger,Object> map;
+ private Map<MutableInteger, T> map;
private MutableInteger mkey;
public TagTable() {
- map = new HashMap<MutableInteger,Object>();
+ map = new HashMap<MutableInteger, T>();
mkey = new MutableInteger();
}
@@ -29,21 +29,21 @@
return map.containsKey(mkey);
}
- public synchronized void put(int key, Object value) {
+ public synchronized void put(int key, T value) {
map.put(new MutableInteger(key), value);
}
- public synchronized Object remove(int key) {
+ public synchronized T remove(int key) {
mkey.setValue(key);
return map.remove(mkey);
}
- public synchronized Object get(int key) {
+ public synchronized T get(int key) {
mkey.setValue(key);
return map.get(mkey);
}
- public Collection<Object> values() {
+ public Collection<T> values() {
return map.values();
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/GSSChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/GSSChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/GSSChannel.java (working copy)
@@ -82,12 +82,14 @@
gssContext.requestAnonymity(false);
gssContext.requestCredDeleg(false);
+ //gssContext.requestConf(false);
gssContext.setOption(GSSConstants.GSS_MODE, GSIConstants.MODE_SSL);
gssContext.setOption(GSSConstants.DELEGATION_TYPE,
GSIConstants.DELEGATION_TYPE_LIMITED);
URI contact = getContact();
socket = (GssSocket) GssSocketFactory.getDefault().createSocket(contact.getHost(),
contact.getPort(), gssContext);
+
socket.setKeepAlive(true);
socket.setSoTimeout(0);
socket.setWrapMode(GSIConstants.MODE_SSL.intValue());
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/KarajanChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/KarajanChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/KarajanChannel.java (working copy)
@@ -24,6 +24,7 @@
public static final int FINAL_FLAG = 0x00000002;
public static final int ERROR_FLAG = 0x00000004;
public static final int COMPRESSED_FLAG = 0x00000008;
+ public static final int SIGNAL_FLAG = 0x00000010;
void sendTaggedData(int i, boolean fin, byte[] bytes);
@@ -41,11 +42,17 @@
void unregisterHandler(int tag);
- void sendTaggedReply(int i, byte[] buf, boolean fin, boolean errorFlag);
+ void sendTaggedReply(int i, byte[] buf, boolean fin, boolean err);
- void sendTaggedReply(int i, byte[] buf, boolean fin, boolean errorFlag, SendCallback cb);
+ void sendTaggedReply(int i, byte[] buf, boolean fin, boolean err, SendCallback cb);
- void sendTaggedReply(int id, ByteBuffer buf, boolean fin, boolean errorFlag, SendCallback cb);
+ void sendTaggedReply(int i, byte[] buf, int flags);
+
+ void sendTaggedReply(int i, byte[] buf, int flags, SendCallback cb);
+
+ void sendTaggedReply(int id, ByteBuffer buf, boolean fin, boolean err, SendCallback cb);
+
+ void sendTaggedReply(int id, ByteBuffer buf, int flags, SendCallback cb);
void registerHandler(RequestHandler handler, int tag);
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractStreamKarajanChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractStreamKarajanChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractStreamKarajanChannel.java (working copy)
@@ -14,21 +14,22 @@
import java.io.OutputStream;
import java.net.URI;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.zip.Adler32;
import org.apache.log4j.Logger;
import org.globus.cog.karajan.workflow.service.RemoteConfiguration;
import org.globus.cog.karajan.workflow.service.RequestManager;
import org.globus.cog.karajan.workflow.service.commands.ChannelConfigurationCommand;
-import edu.emory.mathcs.backport.java.util.Collections;
-
public abstract class AbstractStreamKarajanChannel extends AbstractKarajanChannel implements
Purgeable {
public static final Logger logger = Logger.getLogger(AbstractStreamKarajanChannel.class);
@@ -36,7 +37,7 @@
public static final int STATE_IDLE = 0;
public static final int STATE_RECEIVING_DATA = 1;
- public static final int HEADER_LEN = 12;
+ public static final int HEADER_LEN = 20;
private InputStream inputStream;
private OutputStream outputStream;
@@ -44,7 +45,7 @@
private final byte[] rhdr;
private byte[] data;
private int dataPointer;
- private int state, tag, flags, len;
+ private int state, tag, flags, len, hcsum, csum;
protected AbstractStreamKarajanChannel(RequestManager requestManager,
ChannelContext channelContext, boolean client) {
@@ -78,10 +79,15 @@
protected abstract void reconnect() throws ChannelException;
- protected synchronized void handleChannelException(Exception e) {
+ protected synchronized boolean handleChannelException(Exception e) {
logger.info("Channel config: " + getChannelContext().getConfiguration());
- ChannelManager.getManager().handleChannelException(this, e);
- close();
+ if (!ChannelManager.getManager().handleChannelException(this, e)) {
+ close();
+ return false;
+ }
+ else {
+ return true;
+ }
}
protected void configure() throws Exception {
@@ -121,11 +127,20 @@
tag = unpack(rhdr, 0);
flags = unpack(rhdr, 4);
len = unpack(rhdr, 8);
+ hcsum = unpack(rhdr, 12);
+ if ((tag ^ flags ^ len) != hcsum) {
+ logger.warn("Header checksum failed. Computed checksum: " +
+ Integer.toHexString(tag ^ flags ^ len) +
+ ", checksum: " + Integer.toHexString(hcsum));
+ return true;
+ }
+ csum = unpack(rhdr, 16);
if (len > 1048576) {
logger.warn("Big len: " + len + " (tag: " + tag + ", flags: " + flags + ")");
data = new byte[1024];
inputStream.read(data);
logger.warn("data: " + ppByteBuf(data));
+ return true;
}
data = new byte[len];
dataPointer = 0;
@@ -143,18 +158,26 @@
if (dataPointer == len) {
dataPointer = 0;
state = STATE_IDLE;
- boolean fin = (flags & FINAL_FLAG) != 0;
- boolean error = (flags & ERROR_FLAG) != 0;
+
+ if (csum != 0) {
+ Adler32 c = new Adler32();
+ c.update(data);
+
+ if (((int) c.getValue()) != csum) {
+ logger.warn("Data checksum failed. Compute checksum: " +
+ Integer.toHexString((int) c.getValue()) + ", checksum: " + Integer.toHexString(csum));
+ }
+ }
byte[] tdata = data;
// don't hold reference from the channel to the data
data = null;
- if ((flags & REPLY_FLAG) != 0) {
+ if (flagIsSet(flags, REPLY_FLAG)) {
// reply
- handleReply(tag, fin, error, len, tdata);
+ handleReply(tag, flags, len, tdata);
}
else {
// request
- handleRequest(tag, fin, error, len, tdata);
+ handleRequest(tag, flags, len, tdata);
}
data = null;
}
@@ -188,7 +211,7 @@
Sender s = sender.get(channel.getClass());
if (s == null) {
- sender.put(channel.getClass(), s = new Sender());
+ sender.put(channel.getClass(), s = new Sender(channel.getClass().getSimpleName()));
s.start();
}
return s;
@@ -210,20 +233,26 @@
}
private static class Sender extends Thread {
- private final LinkedList<SendEntry> queue;
+ private final BlockingQueue<SendEntry> queue;
private final byte[] shdr;
+ private final String name;
- public Sender() {
- super("Sender");
- queue = new LinkedList<SendEntry>();
+ public Sender(String name) {
+ super("Sender " + name);
+ this.name = name;
+ queue = new LinkedBlockingQueue<SendEntry>();
setDaemon(true);
shdr = new byte[HEADER_LEN];
}
- public synchronized void enqueue(int tag, int flags, byte[] data,
+ public void enqueue(int tag, int flags, byte[] data,
AbstractStreamKarajanChannel channel, SendCallback cb) {
- queue.addLast(new SendEntry(tag, flags, data, channel, cb));
- notifyAll();
+ try {
+ queue.put(new SendEntry(tag, flags, data, channel, cb));
+ }
+ catch (InterruptedException e) {
+ logger.warn("Interrupted", e);
+ }
}
public void run() {
@@ -232,17 +261,14 @@
SendEntry e;
while (true) {
long now = System.currentTimeMillis();
- synchronized (this) {
- while (queue.isEmpty()) {
- wait();
- }
- e = queue.removeFirst();
- if (now - last > 10000) {
- logger.info("Sender " + System.identityHashCode(this) + " queue size: "
- + queue.size());
- last = now;
- }
+
+ e = queue.take();
+ if (now - last > 10000) {
+ logger.info("Sender " + name + " queue size: "
+ + queue.size());
+ last = now;
}
+
try {
send(e.tag, e.flags, e.data, e.channel.getOutputStream());
if (e.cb != null) {
@@ -252,23 +278,22 @@
catch (IOException ex) {
logger.info("Channel IOException", ex);
try {
- synchronized (this) {
- queue.addFirst(e);
+ if (e.channel.handleChannelException(ex)) {
+ queue.put(e);
}
- e.channel.handleChannelException(ex);
}
catch (Exception exx) {
logger.warn("Channel threw exception while handling channel exception", exx);
}
}
catch (Exception ex) {
- ex.printStackTrace();
+ logger.warn("Caught exception while sending data", ex);
try {
e.channel.getChannelContext().getRegisteredCommand(e.tag).errorReceived(
null, ex);
}
catch (Exception exx) {
- logger.warn(exx);
+ logger.warn("Exception", exx);
}
}
}
@@ -291,11 +316,16 @@
}
}
}
+
private void send(int tag, int flags, byte[] data, OutputStream os) throws IOException {
pack(shdr, 0, tag);
pack(shdr, 4, flags);
pack(shdr, 8, data.length);
+ pack(shdr, 12, tag ^ flags ^ data.length);
+ Adler32 csum = new Adler32();
+ csum.update(data);
+ pack(shdr, 16, (int) csum.getValue());
synchronized (os) {
os.write(shdr);
os.write(data);
@@ -330,7 +360,6 @@
private boolean terminated;
private int id;
- @SuppressWarnings("unchecked")
public Multiplexer(int id) {
super("Channel multiplexer " + id);
this.id = id;
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/PerformanceDiagnosticInputStream.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/PerformanceDiagnosticInputStream.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/PerformanceDiagnosticInputStream.java (working copy)
@@ -28,15 +28,14 @@
public void run() {
count++;
String s;
- logger.info(s = "Total transferred: " + units(bytes) + "B, current rate: "
+ logger.info(s = "[IN] Total transferred: " + units(bytes) + "B, current rate: "
+ units(bytes - last) + "B/s, average rate: " + units(bytes / count)
+ "B/s");
- System.out.println("[IN]: " + s);
- System.out.println("[MEM] Heap total: "
+ logger.info(s = "[MEM] Heap total: "
+ units(Runtime.getRuntime().totalMemory())
- + "MB, Heap used: "
+ + "B, Heap used: "
+ units(Runtime.getRuntime().totalMemory()
- - Runtime.getRuntime().freeMemory()) + "MB");
+ - Runtime.getRuntime().freeMemory()) + "B");
last = bytes;
}
});
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/ChannelManager.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/ChannelManager.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/ChannelManager.java (working copy)
@@ -259,31 +259,40 @@
return meta;
}
- public void handleChannelException(KarajanChannel channel, Exception e) {
+ /**
+ * Returns <code>true</code> if this channel can still transmit after this
+ * exception
+ */
+ public boolean handleChannelException(KarajanChannel channel, Exception e) {
logger.info("Handling channel exception", e == null ? new Throwable() : e);
if (channel.isOffline()) {
logger.info("Channel already shut down");
- return;
+ return false;
}
channel.setLocalShutdown();
ChannelContext ctx = channel.getChannelContext();
RemoteConfiguration.Entry config = ctx.getConfiguration();
+ boolean canContinue;
try {
if (config != null && config.hasOption(RemoteConfiguration.RECONNECT)) {
buffer(channel);
channel.close();
asyncReconnect(channel, e);
+ canContinue = true;
}
else {
channel.close();
shutdownChannel(channel);
+ canContinue = false;
}
}
catch (Exception e2) {
logger.info("Failed to shut down channel", e2);
+ canContinue = false;
}
ctx.channelShutDown(e);
logger.info("Channel exception handled");
+ return canContinue;
}
private void asyncReconnect(final KarajanChannel channel, final Exception e) {
@@ -372,7 +381,7 @@
unregisterChannel(getMetaChannel(ctx));
}
synchronized (channels) {
- channels.remove(new HostCredentialPair("id://" + ctx.getChannelID(), ctx.getUserContext().getCredential()));
+ channels.remove(new HostCredentialPair("id://" + ctx.getChannelID(), (GSSCredential) null));
}
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/NullChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/NullChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/NullChannel.java (working copy)
@@ -26,6 +26,10 @@
protected void configureHeartBeat() {
// override to do nothing
}
+
+ public void configureTimeoutChecks() {
+ // do nothing
+ }
public void sendTaggedData(int i, int flags, byte[] bytes, SendCallback cb) {
if (!sink) {
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/UDPChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/UDPChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/UDPChannel.java (working copy)
@@ -156,16 +156,14 @@
if (checksum != actual) {
throw new ChannelException("Checksum failed. Expected " + checksum + " got " + actual);
}
- boolean fin = (flags & FINAL_FLAG) != 0;
- boolean error = (flags & ERROR_FLAG) != 0;
byte[] data = new byte[len - HDRLEN];
System.arraycopy(recvbuf, HDRLEN, data, 0, len - HDRLEN);
if ((flags & REPLY_FLAG) != 0) {
// reply
- handleReply(tag, fin, error, len - HDRLEN, data);
+ handleReply(tag, flags, len - HDRLEN, data);
}
else {
- handleRequest(tag, fin, error, len - HDRLEN, data);
+ handleRequest(tag, flags, len - HDRLEN, data);
}
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractKarajanChannel.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractKarajanChannel.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/channels/AbstractKarajanChannel.java (working copy)
@@ -14,6 +14,7 @@
import java.io.InputStream;
import java.net.URI;
import java.nio.ByteBuffer;
+import java.util.Collection;
import java.util.TimerTask;
import org.apache.log4j.Logger;
@@ -22,6 +23,7 @@
import org.globus.cog.karajan.workflow.service.RemoteConfiguration;
import org.globus.cog.karajan.workflow.service.RemoteConfiguration.Entry;
import org.globus.cog.karajan.workflow.service.RequestManager;
+import org.globus.cog.karajan.workflow.service.RequestReply;
import org.globus.cog.karajan.workflow.service.Service;
import org.globus.cog.karajan.workflow.service.UserContext;
import org.globus.cog.karajan.workflow.service.commands.Command;
@@ -33,6 +35,8 @@
// some random spread to avoid sending all heartbeats at once
public static final int DEFAULT_HBI_INITIAL_SPREAD = 10;
public static final int DEFAULT_HBI_SPREAD = 10;
+
+ public static final int TIMEOUT_CHECK_INTERVAL = 1;
private ChannelContext context;
private volatile int usageCount, longTermUsageCount;
@@ -52,6 +56,7 @@
// registeredMaps = new LinkedList();
this.client = client;
configureHeartBeat();
+ configureTimeoutChecks();
}
protected void configureHeartBeat() {
@@ -63,9 +68,9 @@
}
}
heartBeatInterval *= 1000;
-
+
boolean controlHeartbeats = isClient() == clientControlsHeartbeats();
-
+
if (!isOffline() && controlHeartbeats) {
scheduleHeartbeats(heartBeatInterval);
}
@@ -89,15 +94,15 @@
scheduleHeartbeatCheck(heartBeatInterval);
}
}
-
+
public void scheduleHeartbeats(int heartBeatInterval) {
TimerTask heartBeatTask;
heartBeatTask = new HeartBeatTask(this);
- context.getTimer().schedule(heartBeatTask,
- heartBeatInterval + (int) (Math.random() * DEFAULT_HBI_INITIAL_SPREAD * 1000),
+ context.getTimer().schedule(heartBeatTask,
+ heartBeatInterval + (int) (Math.random() * DEFAULT_HBI_INITIAL_SPREAD * 1000),
heartBeatInterval + (int) (Math.random() * DEFAULT_HBI_SPREAD * 1000));
}
-
+
public void scheduleHeartbeatCheck(int heartBeatInterval) {
TimerTask heartBeatTask;
int mult = 2;
@@ -105,6 +110,33 @@
context.getTimer().schedule(heartBeatTask, mult * heartBeatInterval,
mult * heartBeatInterval);
}
+
+ public void configureTimeoutChecks() {
+ context.getTimer().schedule(new TimerTask() {
+ public void run() {
+ checkTimeouts();
+ }},
+ TIMEOUT_CHECK_INTERVAL * 1000, TIMEOUT_CHECK_INTERVAL * 1000);
+ }
+
+ protected void checkTimeouts() {
+ checkTimeouts(context.getActiveCommands());
+ checkTimeouts(context.getActiveHandlers());
+ }
+
+ private void checkTimeouts(Collection<? extends RequestReply> l) {
+ long now = System.currentTimeMillis();
+ for (RequestReply r : l) {
+ if (now - r.getLastTime() > r.getTimeout()) {
+ try {
+ r.handleTimeout();
+ }
+ catch (Exception e) {
+ logger.warn("Error handling timeout", e);
+ }
+ }
+ }
+ }
protected boolean clientControlsHeartbeats() {
return true;
@@ -131,6 +163,16 @@
context.unregisterHandler(tag);
}
+ @Override
+ public void sendTaggedReply(int tag, byte[] data, boolean fin, boolean err) {
+ sendTaggedReply(tag, data, (fin ? FINAL_FLAG : 0) + (err ? ERROR_FLAG : 0));
+ }
+
+ @Override
+ public void sendTaggedReply(int tag, byte[] data, boolean fin, boolean err, SendCallback cb) {
+ sendTaggedReply(tag, data, (fin ? FINAL_FLAG : 0) + (err ? ERROR_FLAG : 0), cb);
+ }
+
public void sendTaggedReply(int tag, byte[] data, boolean fin) {
sendTaggedReply(tag, data, fin, false);
}
@@ -151,36 +193,33 @@
sendTaggedData(i, flags, bytes, null);
}
- public void sendTaggedReply(int tag, byte[] data, boolean fin, boolean err) {
- sendTaggedReply(tag, data, fin, err, null);
+ public void sendTaggedReply(int tag, byte[] data, int flags) {
+ sendTaggedReply(tag, data, flags, null);
}
- public void sendTaggedReply(int tag, byte[] data, boolean fin, boolean err, SendCallback cb) {
+ public void sendTaggedReply(int tag, byte[] data, int flags, SendCallback cb) {
if (logger.isDebugEnabled()) {
- logger.debug(this + " REPL>: tag = " + tag + ", fin = " + fin + ", datalen = "
+ logger.debug(this + " REPL>: tag = " + tag + ", fin = " + flagIsSet(flags, FINAL_FLAG) + ", datalen = "
+ data.length + ", data = " + ppByteBuf(data));
}
- int flags = REPLY_FLAG;
- if (fin) {
- flags |= FINAL_FLAG;
- }
- if (err) {
- flags |= ERROR_FLAG;
- }
- sendTaggedData(tag, flags, data, cb);
+
+ sendTaggedData(tag, flags | REPLY_FLAG, data, cb);
}
+
+ public void sendTaggedReply(int id, ByteBuffer buf, boolean fin, boolean err, SendCallback cb) {
+ sendTaggedReply(id, buf, (fin ? FINAL_FLAG : 0) + (err ? ERROR_FLAG : 0), cb);
+ }
- public void sendTaggedReply(int id, ByteBuffer buf, boolean fin, boolean errorFlag,
- SendCallback cb) {
+ public void sendTaggedReply(int id, ByteBuffer buf, int flags, SendCallback cb) {
// TODO this should probably be changed to use buffers more efficiently
if (buf.hasArray() && (buf.limit() == buf.capacity())) {
- sendTaggedReply(id, buf.array(), fin, errorFlag, cb);
+ sendTaggedReply(id, buf.array(), flags, cb);
}
else {
byte[] bbuf = new byte[buf.limit()];
buf.get(bbuf);
buf.rewind();
- sendTaggedReply(id, bbuf, fin, errorFlag, cb);
+ sendTaggedReply(id, bbuf, flags, cb);
}
}
@@ -199,7 +238,7 @@
public ChannelContext getChannelContext() {
return context;
}
-
+
public final UserContext getUserContext() {
return context.getUserContext();
}
@@ -237,7 +276,7 @@
i += (buf[offset + 3] & 0xff) << 24;
return i;
}
-
+
/**
Pretty-print byte buffer
*/
@@ -342,20 +381,28 @@
}
- protected void handleReply(int tag, boolean fin, boolean error, int len, byte[] data) {
+ protected void handleReply(int tag, int flags, int len, byte[] data) {
if (logger.isDebugEnabled()) {
- logger.debug(this + " REPL<: tag = " + tag + ", fin = " + fin + ", err = " + error
+ logger.debug(this + " REPL<: tag = " + tag + ", fin = " +
+ flagIsSet(flags, FINAL_FLAG) + ", err = " + flagIsSet(flags, ERROR_FLAG)
+ ", datalen = " + len + ", data = " + ppByteBuf(data));
}
Command cmd = getChannelContext().getRegisteredCommand(tag);
if (cmd != null) {
try {
- cmd.replyReceived(fin, error, data);
+ boolean fin = finalFlagIsSet(flags);
+ boolean err = errorFlagIsSet(flags);
+ if (flagIsSet(flags, SIGNAL_FLAG)) {
+ cmd.handleSignal(data);
+ }
+ else {
+ cmd.replyReceived(fin, err, data);
+ }
if (fin) {
if (logger.isDebugEnabled()) {
logger.debug(this + " REPL: " + cmd);
}
- if (error) {
+ if (err) {
cmd.errorReceived();
}
else {
@@ -378,22 +425,45 @@
}
}
+ protected boolean flagIsSet(int flags, int mask) {
+ return (flags & mask) != 0;
+ }
+
+ protected boolean finalFlagIsSet(int flags) {
+ return (flags & FINAL_FLAG) != 0;
+ }
+
+ protected boolean errorFlagIsSet(int flags) {
+ return (flags & ERROR_FLAG) != 0;
+ }
+
protected void unregisteredSender(int tag) {
logger.warn(getName() + " Recieved reply to unregistered sender. Tag: " + tag);
}
- protected void handleRequest(int tag, boolean fin, boolean error, int len, byte[] data) {
+ protected void handleRequest(int tag, int flags, int len, byte[] data) {
if (logger.isDebugEnabled()) {
- logger.debug(this + " REQ<: tag = " + tag + ", fin = " + fin + ", err = " + error
+ logger.debug(this + " REQ<: tag = " + tag + ", fin = " +
+ flagIsSet(flags, FINAL_FLAG) + ", err = " + flagIsSet(flags, ERROR_FLAG)
+ ", datalen = " + len + ", data = " + ppByteBuf(data));
}
RequestHandler handler = getChannelContext().getRegisteredHandler(tag);
+ boolean fin = finalFlagIsSet(flags);
+ boolean err = errorFlagIsSet(flags);
try {
if (handler != null) {
- handler.register(this);
- handler.dataReceived(fin, error, data);
+ if (flagIsSet(flags, SIGNAL_FLAG)) {
+ handler.handleSignal(data);
+ }
+ else {
+ handler.dataReceived(fin, err, data);
+ }
}
else {
+ if (flagIsSet(flags, SIGNAL_FLAG)) {
+ logger.warn("Got signal for unregistered tag (" + tag + "): " + new String(data));
+ return;
+ }
try {
handler = getRequestManager().handleInitialRequest(data);
handler.setId(tag);
@@ -409,7 +479,7 @@
if (logger.isDebugEnabled()) {
logger.debug(this + " REQ: " + handler);
}
- if (error) {
+ if (err) {
handler.errorReceived();
}
else {
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/handlers/RequestHandler.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/handlers/RequestHandler.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/handlers/RequestHandler.java (working copy)
@@ -10,11 +10,13 @@
package org.globus.cog.karajan.workflow.service.handlers;
import java.util.Collection;
+import java.util.Date;
import java.util.Iterator;
import org.apache.log4j.Logger;
import org.globus.cog.karajan.workflow.service.ProtocolException;
import org.globus.cog.karajan.workflow.service.RequestReply;
+import org.globus.cog.karajan.workflow.service.TimeoutException;
import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
public abstract class RequestHandler extends RequestReply {
@@ -34,6 +36,7 @@
}
protected void sendReply() throws ProtocolException {
+ setLastTime(System.currentTimeMillis());
send();
replySent = true;
}
@@ -102,10 +105,22 @@
}
protected String ppInData(String prefix) {
- return ppData(prefix+"< ", getInCmd(), getInDataChunks());
+ return ppData(prefix + "< ", getInCmd(), getInDataChunks());
}
-
+
public String toString() {
- return "Handler(" + getInCmd() + ")";
+ return "Handler(" + getId() + ", " + getInCmd() + ")";
}
+
+ public void handleTimeout() {
+ if (isInDataReceived()) {
+ return;
+ }
+ setLastTime(Long.MAX_VALUE);
+ getChannel().unregisterHandler(getId());
+ String msg = this + ": timed out receiving request. Last time "
+ + DF.format(new Date(getLastTime())) + ", now: " + DF.format(new Date());
+ logger.info(msg);
+ errorReceived("Timeout", new TimeoutException(msg));
+ }
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/ReplyTimeoutException.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/ReplyTimeoutException.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/ReplyTimeoutException.java (working copy)
@@ -1,30 +0,0 @@
-//----------------------------------------------------------------------
-//This code is developed as part of the Java CoG Kit project
-//The terms of the license can be found at http://www.cogkit.org/license
-//This message may not be removed or altered.
-//----------------------------------------------------------------------
-
-/*
- * Created on Aug 2, 2005
- */
-package org.globus.cog.karajan.workflow.service;
-
-public class ReplyTimeoutException extends ProtocolException {
- private static final long serialVersionUID = -6781619140427115780L;
-
- public ReplyTimeoutException() {
- super();
- }
-
- public ReplyTimeoutException(String message) {
- super(message);
- }
-
- public ReplyTimeoutException(String message, Throwable cause) {
- super(message, cause);
- }
-
- public ReplyTimeoutException(Throwable cause) {
- super(cause);
- }
-}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/commands/Command.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/commands/Command.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/commands/Command.java (working copy)
@@ -10,18 +10,15 @@
package org.globus.cog.karajan.workflow.service.commands;
import java.io.IOException;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.Timer;
-import java.util.TimerTask;
import org.apache.log4j.Logger;
import org.globus.cog.karajan.workflow.service.ProtocolException;
-import org.globus.cog.karajan.workflow.service.ReplyTimeoutException;
import org.globus.cog.karajan.workflow.service.RequestReply;
+import org.globus.cog.karajan.workflow.service.TimeoutException;
import org.globus.cog.karajan.workflow.service.channels.ChannelIOException;
import org.globus.cog.karajan.workflow.service.channels.ChannelManager;
import org.globus.cog.karajan.workflow.service.channels.KarajanChannel;
@@ -36,17 +33,12 @@
timer = new Timer(true);
}
- public static final DateFormat DF = new SimpleDateFormat("yyMMdd-HHmmss.SSS");
-
- public static final int DEFAULT_REPLY_TIMEOUT = 120 * 1000;
public static final int DEFAULT_MAX_RETRIES = 2;
- private int replyTimeout = DEFAULT_REPLY_TIMEOUT;
private int maxRetries = DEFAULT_MAX_RETRIES;
private Callback cb;
private String errorMsg;
private Exception exception;
- private Timeout timeout;
private int retries;
private long sendTime;
private long sendReqTime;
@@ -64,13 +56,13 @@
this.cb = cb;
}
- public void waitForReply() throws ReplyTimeoutException {
+ public void waitForReply() throws TimeoutException {
synchronized (this) {
if (!this.isInDataReceived()) {
- long left = replyTimeout;
+ long left = getTimeout();
while (!this.isInDataReceived()) {
if (left <= 0) {
- throw new ReplyTimeoutException();
+ throw new TimeoutException();
}
try {
wait(left);
@@ -78,7 +70,7 @@
catch (InterruptedException e) {
e.printStackTrace();
}
- left = sendTime == 0 ? 1000 : replyTimeout
+ left = sendTime == 0 ? 1000 : getTimeout()
- (System.currentTimeMillis() - sendTime);
}
}
@@ -106,8 +98,7 @@
}
public void send(boolean err) throws ProtocolException {
- sendReqTime = System.currentTimeMillis();
- cancelTimeout();
+
KarajanChannel channel = getChannel();
if (logger.isDebugEnabled()) {
logger.debug("Sending " + this + " on " + channel);
@@ -137,6 +128,8 @@
channel.sendTaggedData(id, !i.hasNext(), buf, !i.hasNext() ? this : null);
}
}
+ sendReqTime = System.currentTimeMillis();
+ setLastTime(sendReqTime);
}
catch (ChannelIOException e) {
reexecute(e.getMessage(), e);
@@ -146,21 +139,11 @@
public void dataSent() {
sendTime = System.currentTimeMillis();
//when using the piped channels the reply will arrive before this method is called
- setupReplyTimeoutChecker();
+ setLastTime(sendTime);
}
+
+ private static boolean shutdownMsg;
- protected synchronized void setupReplyTimeoutChecker() {
- if (!isInDataReceived()) {
- timeout = new Timeout();
- try {
- timer.schedule(timeout, replyTimeout);
- }
- catch (IllegalStateException e) {
- logger.info("Timer cancelled due to JVM shutting down. Going without timeouts.");
- }
- }
- }
-
public byte[] execute(KarajanChannel channel) throws ProtocolException, IOException {
send(channel);
waitForReply();
@@ -187,14 +170,6 @@
send();
}
- public int getReplyTimeout() {
- return replyTimeout;
- }
-
- public void setReplyTimeout(int replyTimeout) {
- this.replyTimeout = replyTimeout;
- }
-
public int getMaxRetries() {
return maxRetries;
}
@@ -203,15 +178,7 @@
this.maxRetries = maxRetries;
}
- private synchronized void cancelTimeout() {
- if (timeout != null) {
- timeout.cancel();
- timeout = null;
- }
- }
-
public void receiveCompleted() {
- cancelTimeout();
if (logger.isDebugEnabled()) {
logger.debug(ppInData("CMD"));
}
@@ -222,7 +189,6 @@
}
public void errorReceived(String msg, Exception t) {
- cancelTimeout();
if (logger.isDebugEnabled()) {
logger.debug(ppInData("CMDERR"));
}
@@ -275,30 +241,25 @@
}
}
}
-
- protected void handleReplyTimeout() {
- timeout = null;
+
+ public void handleTimeout() {
if (isInDataReceived()) {
return;
}
logger.warn(this
+ ": handling reply timeout; sendReqTime="
+ DF.format(new Date(sendReqTime)) + ", sendTime=" + DF.format(new Date(sendTime))
- + ", now=" + DF.format(new Date()));
- reexecute("Reply timeout", new ReplyTimeoutException());
+ + ", now=" + DF.format(new Date()) + ", channel=" + getChannel());
+ getChannel().unregisterCommand(this);
+ //reexecute("Reply timeout", new TimeoutException());
}
- private class Timeout extends TimerTask {
- public void run() {
- handleReplyTimeout();
- }
+ protected long getSendReqTime() {
+ return sendReqTime;
+ }
- public boolean cancel() {
- if (logger.isDebugEnabled()) {
- logger.debug("SRC " + System.identityHashCode(timeout), new Exception());
- }
- return super.cancel();
- }
+ protected void setSendReqTime(long sendReqTime) {
+ this.sendReqTime = sendReqTime;
}
public String toString() {
Index: modules/karajan/src/org/globus/cog/karajan/workflow/service/commands/HeartBeatCommand.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/service/commands/HeartBeatCommand.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/service/commands/HeartBeatCommand.java (working copy)
@@ -9,11 +9,14 @@
*/
package org.globus.cog.karajan.workflow.service.commands;
+import org.apache.log4j.Logger;
import org.globus.cog.karajan.workflow.service.ProtocolException;
import org.globus.cog.karajan.workflow.service.handlers.HeartBeatHandler;
public class HeartBeatCommand extends Command {
+ public static final Logger logger = Logger.getLogger(HeartBeatCommand.class);
+
private long start;
private static int sid;
private int id;
@@ -31,5 +34,10 @@
public void replyReceived(boolean fin, boolean err, byte[] data) throws ProtocolException {
super.replyReceived(fin, err, data);
+ if (logger.isInfoEnabled()) {
+ long rst = Long.parseLong(getInDataAsString(0));
+ long now = System.currentTimeMillis();
+ logger.info(getChannel() + " up latency: " + (now - rst) + "ms, rtt: " + (now - start) + "ms");
+ }
}
}
Index: modules/karajan/src/org/globus/cog/karajan/workflow/futures/ChannelSplitter.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/futures/ChannelSplitter.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/futures/ChannelSplitter.java (working copy)
@@ -38,7 +38,6 @@
- @Override
public void futureModified(Future f, VariableStack stack) {
FutureVariableArguments in = (FutureVariableArguments) f;
while(in.available() > 0) {
Index: modules/karajan/src/org/globus/cog/karajan/workflow/futures/ForwardArgumentFuture.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/workflow/futures/ForwardArgumentFuture.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/workflow/futures/ForwardArgumentFuture.java (working copy)
@@ -114,7 +114,6 @@
}
}
- @Override
public void futureModified(Future f, VariableStack stack) {
synchronized (vargs) {
try {
@@ -136,4 +135,4 @@
this.exception = e;
actions();
}
-}
\ No newline at end of file
+}
Index: modules/karajan/src/org/globus/cog/karajan/util/ElementProperty.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/util/ElementProperty.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/util/ElementProperty.java (working copy)
@@ -130,7 +130,7 @@
this.name = ident.getName();
}
- public Object getValue(VariableStack stack) throws VariableNotFoundException {
+ public synchronized Object getValue(VariableStack stack) throws VariableNotFoundException {
switch (frame) {
case UNINITIALIZED:
case VariableStack.NO_FRAME:
Index: modules/karajan/src/org/globus/cog/karajan/scheduler/AbstractScheduler.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/scheduler/AbstractScheduler.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/scheduler/AbstractScheduler.java (working copy)
@@ -169,7 +169,7 @@
}
}
finally {
- jobListeners.release();
+ jobListeners.release(i);
}
}
}
Index: modules/karajan/src/org/globus/cog/karajan/scheduler/submitQueue/AbstractSubmitQueue.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/scheduler/submitQueue/AbstractSubmitQueue.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/scheduler/submitQueue/AbstractSubmitQueue.java (working copy)
@@ -9,9 +9,10 @@
*/
package org.globus.cog.karajan.scheduler.submitQueue;
-import edu.emory.mathcs.backport.java.util.Queue;
-import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
/**
* Base class for submit queues. It uses a generic throttle value.
* Progress through the queues is triggered using the {@link step()} method
Index: modules/karajan/src/org/globus/cog/karajan/scheduler/WeightedHostScoreScheduler.java
===================================================================
--- modules/karajan/src/org/globus/cog/karajan/scheduler/WeightedHostScoreScheduler.java (revision 3354)
+++ modules/karajan/src/org/globus/cog/karajan/scheduler/WeightedHostScoreScheduler.java (working copy)
@@ -251,6 +251,10 @@
}
return selected.getHost();
}
+
+ public synchronized boolean allOverloaded() {
+ return sorted.allOverloaded();
+ }
public void releaseContact(Contact contact) {
if (logger.isDebugEnabled()) {
Index: modules/karajan/.classpath
===================================================================
--- modules/karajan/.classpath (revision 3354)
+++ modules/karajan/.classpath (working copy)
@@ -1,18 +1,16 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="resources"/>
- <classpathentry kind="src" path="/grapheditor"/>
- <classpathentry kind="src" path="/util"/>
- <classpathentry exported="true" kind="lib" path="lib/xpp3-1.1.3.4d_b4_min.jar" sourcepath="/home/mike/work/sources/xpp3-1.1.3.4.D/src"/>
- <classpathentry exported="true" kind="lib" path="lib/xstream-1.1.1-patched.jar" sourcepath="/home/mike/work/sources/xstream-1.1.1/src/java"/>
- <classpathentry kind="src" path="/abstraction"/>
- <classpathentry kind="lib" path="etc"/>
- <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry combineaccessrules="false" kind="src" path="/abstraction-provider-gt2"/>
- <classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/backport-util-concurrent"/>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
- <classpathentry kind="lib" path="/util/lib/backport-util-concurrent.jar"/>
- <classpathentry kind="output" path=".build"/>
-</classpath>
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="src" path="resources"/>
+ <classpathentry kind="src" path="/util"/>
+ <classpathentry exported="true" kind="lib" path="lib/xpp3-1.1.3.4d_b4_min.jar" sourcepath="/home/mike/work/sources/xpp3-1.1.3.4.D/src"/>
+ <classpathentry exported="true" kind="lib" path="lib/xstream-1.1.1-patched.jar" sourcepath="/home/mike/work/sources/xstream-1.1.1/src/java"/>
+ <classpathentry kind="src" path="/abstraction"/>
+ <classpathentry kind="lib" path="etc"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/abstraction-provider-gt2"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/jglobus"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/backport-util-concurrent"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
+ <classpathentry kind="output" path=".build"/>
+</classpath>
Index: modules/all/dependencies.xml
===================================================================
--- modules/all/dependencies.xml (revision 3354)
+++ modules/all/dependencies.xml (working copy)
@@ -26,9 +26,6 @@
<property name="module" value="certmanagement"/>
</ant>
<ant antfile="${main.buildfile}" target="dep">
- <property name="module" value="gridfaces"/>
- </ant>
- <ant antfile="${main.buildfile}" target="dep">
<property name="module" value="examples"/>
</ant>
</target>
Index: modules/abstraction/.classpath
===================================================================
--- modules/abstraction/.classpath (revision 3354)
+++ modules/abstraction/.classpath (working copy)
@@ -10,7 +10,6 @@
<classpathentry exported="true" kind="src" path="/abstraction-provider-gt4_0_0"/>
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/abstraction-provider-local"/>
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/abstraction-provider-condor"/>
- <classpathentry combineaccessrules="false" exported="true" kind="src" path="/abstraction-provider-dcache"/>
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/abstraction-provider-localscheduler"/>
<classpathentry exported="true" kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j-1.2.8"/>
<classpathentry kind="output" path=".build"/>
Index: modules/provider-condor/.classpath
===================================================================
--- modules/provider-condor/.classpath (revision 3354)
+++ modules/provider-condor/.classpath (working copy)
@@ -9,6 +9,6 @@
<accessrule kind="nonaccessible" pattern="**/CVS/*"/>
</accessrules>
</classpathentry>
- <classpathentry kind="lib" path="/util/lib/log4j-1.2.8.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/util/.classpath
===================================================================
--- modules/util/.classpath (revision 3354)
+++ modules/util/.classpath (working copy)
@@ -4,8 +4,6 @@
<classpathentry kind="lib" path="etc"/>
<classpathentry exported="true" kind="lib" path="lib/jakarta-regexp-1.2.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j-1.2.8"/>
- <classpathentry exported="true" kind="lib" path="lib/log4j-1.2.16.jar"/>
- <classpathentry exported="true" kind="lib" path="lib/log4j-1.2.8.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/log4j"/>
<classpathentry kind="output" path=".build"/>
</classpath>
Index: modules/util/lib/backport-util-concurrent.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: modules/util/lib/log4j-1.2.16.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: modules/util/lib/log4j-1.2.8.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: modules/util/src/org/globus/cog/util/CopyOnWriteHashSet.java
===================================================================
--- modules/util/src/org/globus/cog/util/CopyOnWriteHashSet.java (revision 3354)
+++ modules/util/src/org/globus/cog/util/CopyOnWriteHashSet.java (working copy)
@@ -41,7 +41,7 @@
public class CopyOnWriteHashSet<T> implements Set<T>, Cloneable {
private Set<T> set = Collections.emptySet();
- private int lock;
+ private int lock;
public int size() {
return set.size();
@@ -55,22 +55,24 @@
return set.contains(o);
}
- public synchronized void release() {
- if (lock > 0) {
- lock--;
- }
+ public synchronized void release(Iterator<T> it) {
+ if (((LIterator) it).set == set) {
+ if (lock > 0) {
+ lock--;
+ }
+ }
}
public synchronized Iterator<T> iterator() {
lock++;
- return set.iterator();
+ return new LIterator(set);
}
public Object[] toArray() {
return set.toArray();
}
- public <T> T[] toArray(T[] a) {
+ public <S> S[] toArray(S[] a) {
return set.toArray(a);
}
@@ -194,11 +196,33 @@
T o = it.next();
tmp.add(o);
}
- release();
+ release(it);
CopyOnWriteHashSet<T> result = new CopyOnWriteHashSet<T>();
result.lock = 0;
result.set = tmp;
return result;
}
+
+ private class LIterator implements Iterator<T> {
+ private Iterator<T> it;
+ public Set<T> set;
+
+ public LIterator(Set<T> set) {
+ this.set = set;
+ this.it = set.iterator();
+ }
+
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ public T next() {
+ return it.next();
+ }
+
+ public void remove() {
+ it.remove();
+ }
+ }
}
Index: modules/util/src/org/globus/cog/util/CopyOnWriteArrayList.java
===================================================================
--- modules/util/src/org/globus/cog/util/CopyOnWriteArrayList.java (revision 3354)
+++ modules/util/src/org/globus/cog/util/CopyOnWriteArrayList.java (working copy)
@@ -26,7 +26,7 @@
public class CopyOnWriteArrayList<T> implements List<T> {
private List<T> list = Collections.emptyList();
- private int lock;
+ private int lock;
public int size() {
return list.size();
@@ -40,22 +40,24 @@
return list.contains(o);
}
- public synchronized void release() {
- if (lock > 0) {
- lock--;
- }
+ public synchronized void release(Iterator<T> it) {
+ if (((LIterator) it).list == list) {
+ if (lock > 0) {
+ lock--;
+ }
+ }
}
public synchronized Iterator<T> iterator() {
lock++;
- return list.iterator();
+ return new LIterator(list);
}
public Object[] toArray() {
return list.toArray();
}
- public <T> T[] toArray(T[] a) {
+ public <S> S[] toArray(S[] a) {
return list.toArray(a);
}
@@ -68,7 +70,6 @@
}
}
- @Override
public synchronized void add(int index, T o) {
if (lock > 0 || list.isEmpty()) {
copyAndAdd(index, o);
@@ -102,7 +103,6 @@
}
}
- @Override
public synchronized T remove(int index) {
if (lock > 0) {
return copyAndRemove(index);
@@ -141,7 +141,6 @@
}
}
- @Override
public boolean addAll(int index, Collection<? extends T> c) {
if (lock > 0 || list.isEmpty()) {
return copyAndAddAll(index, c);
@@ -224,40 +223,53 @@
return list.toString();
}
- @Override
public T get(int index) {
return list.get(index);
}
- @Override
public int indexOf(Object o) {
return list.indexOf(o);
}
- @Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
- @Override
public ListIterator<T> listIterator() {
throw new UnsupportedOperationException();
}
- @Override
public ListIterator<T> listIterator(int index) {
throw new UnsupportedOperationException();
}
- @Override
public T set(int index, T o) {
return list.set(index, o);
}
- @Override
public List<T> subList(int fromIndex, int toIndex) {
throw new UnsupportedOperationException();
};
-
+ private class LIterator implements Iterator<T> {
+ public List<T> list;
+ private Iterator<T> it;
+
+ public LIterator(List<T> list){
+ this.list = list;
+ this.it = list.iterator();
+ }
+
+ public boolean hasNext() {
+ return it.hasNext();
+ }
+
+ public T next() {
+ return it.next();
+ }
+
+ public void remove() {
+ it.remove();
+ }
+ }
}
Property changes on: .
___________________________________________________________________
Modified: svn:mergeinfo
Merged /branches/4.1.9/src/cog:r3174-3353
More information about the Swift-commit
mailing list