November 9 2012 Friday
Experimenting DOTS task vs. Java Agent
DOTS (Domino OSGi Tasklet Service) project has been contributed into OpenNTF last year. Basically, it provides a way to create server tasks for Java developers.
This is huge. Basically we could run our Java code in a similar way with a couple of other techniques, but DOTS provide many advantages. I'll dive deep on this in a seperate blog post. For now, take it as a teaser :)
You can refer to Niklas's blog entry to setup DOTS in your environment.
For this experiment, I'm using an exploded version of FakeNames database by David Leedy. In the past, I have duplicated all contents for several times and I'm still using it to crash my server :)
First, I have created a 'terrible' Java agent which does nothing.
As I said before, it does nothing but counting people that has a first name starts with "Sa". So it does something, consume memory and CPU. Who cares :)
Then I implemented the same code as a DOTS task:
Now, results:
You got the idea. The same Java routine runs in 143 seconds as a Java agent and 41 seconds as a DOTS task*.
This is huge. Basically we could run our Java code in a similar way with a couple of other techniques, but DOTS provide many advantages. I'll dive deep on this in a seperate blog post. For now, take it as a teaser :)
You can refer to Niklas's blog entry to setup DOTS in your environment.
For this experiment, I'm using an exploded version of FakeNames database by David Leedy. In the past, I have duplicated all contents for several times and I'm still using it to crash my server :)
First, I have created a 'terrible' Java agent which does nothing.
import java.util.Date;
import lotus.domino.AgentBase;
import lotus.domino.AgentContext;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.Session;
import lotus.domino.View;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Date startTime=new Date();
Database db=getSession().getDatabase("", "test/fakenames.nsf", false);
longJob(db);
long duration=((new Date().getTime()) - startTime.getTime())/1000;
System.out.println("Finished in " + String.valueOf(duration) + " secs... - ");
} catch(Exception e) {
e.printStackTrace();
}
}
public void longJob(Database db) throws NotesException {
int count=0;
View view=db.getView("byName");
System.out.println(view.getTopLevelEntryCount());
for(int i=0; i < view.getTopLevelEntryCount(); i++) {
Document doc=view.getNthDocument(i);
if(doc!=null) {
if(doc.getItemValueString("FirstName").startsWith("Sa")) {
count++;
}
doc.recycle();
}
}
view.recycle();
System.out.println(count);
}
}
As I said before, it does nothing but counting people that has a first name starts with "Sa". So it does something, consume memory and CPU. Who cares :)
Then I implemented the same code as a DOTS task:
import java.util.Date;
import lotus.domino.Database;
import lotus.domino.Document;
import lotus.domino.NotesException;
import lotus.domino.View;
import org.eclipse.core.runtime.IProgressMonitor;
import com.ibm.dots.annotation.RunOnStart;
import com.ibm.dots.task.AbstractServerTaskExt;
import com.ibm.dots.task.RunWhen;
public class AnnotatedTasklet extends AbstractServerTaskExt {
public AnnotatedTasklet() {
}
public void dispose() throws NotesException {
}
@Override
protected void doRun(RunWhen runWhen, IProgressMonitor monitor) throws NotesException {
}
@RunOnStart
public void runOnStart( IProgressMonitor monitor ) throws NotesException {
Date startTime=new Date();
Database db=getSession().getDatabase("", "test/fakenames.nsf", false);
longJob(db);
long duration=((new Date().getTime()) - startTime.getTime())/1000;
logMessage("Finished in " + String.valueOf(duration) + " secs...");
}
public void longJob(Database db) throws NotesException {
int count=0;
View view=db.getView("byName");
System.out.println(view.getTopLevelEntryCount());
for(int i=0; i < view.getTopLevelEntryCount(); i++) {
Document doc=view.getNthDocument(i);
if(doc!=null) {
if(doc.getItemValueString("FirstName").startsWith("Sa")) {
count++;
}
doc.recycle();
}
}
view.recycle();
System.out.println(count);
}
}
Now, results:
> tell amgr run "test\XPagescrash.nsf" 'LongJobAgent'
09.11.2012 19:38:39 JVM: Java Virtual Machine initialized.
09.11.2012 19:38:39 AMgr: Start executing agent 'LongJobAgent' in 'test\XPagescrash.nsf'
09.11.2012 19:38:39 Agent Manager: Agent printing: 181349
09.11.2012 19:41:02 Agent Manager: Agent printing: 2227
09.11.2012 19:41:02 Agent Manager: Agent printing: Finished in 143 secs... -
09.11.2012 19:41:02 AMgr: Agent 'LongJobAgent' in 'test\XPagescrash.nsf' completed execution
> load dots
> Listening for transport dt_socket at address: 8001
> WARNING: Using pde configuration New_configuration located in C:\Lotus\Domino\Data\domino\workspace-dots\pde.launch.ini
09.11.2012 19:42:40 Domino OSGi Tasklet Container started ( profile DOTS )
> 181349
> 2227
09.11.2012 19:43:22 [DOTS] (annotated) Finished in 41 secs...
You got the idea. The same Java routine runs in 143 seconds as a Java agent and 41 seconds as a DOTS task*.
(*) Clinical trials from Developi labs :)
Comments (4)
@Tommy, Interestingly, Amgr consumes more CPU and less memory.
We have discussed this. Nathan commented about the JVM and I think that could be the source of this difference.
DOTS is running on a persistent JVM. However, each Java agent call causes a JVM instance and it prepares all objects, NRPC connections from the scratch. We have calculated the runtime only. Looking to the start-up times, we can see amgr has an additional overhead there.
Do you know why there's such big difference? Did you check the cpu usage on the server when running the two tasks?
Could it be some kind of CPU quota that limits the agent?
@Fero, in fact, getNthDocument() is a really fast method. Since the database is not modified, I don't think autoupdate will effect.
However, in a normal database, if you are using view.getNthDocument(), autoupdate should be false to prevent bad things :)
Of course, I suggest view navigator :)