2012/06/01

Cache makes NetKernel go round

It was a long climb up from the earth's core. Today I have a small technical tip. Here's the code snippet we start with :

public void onSource(INKFRequestContext aContext) throws Exception {
   String lFilename = aContext.getThisRequest().getArgumentValue("filename");
   String lResult;

   if (!aContext.exists("pds:/rsk/" + lFilename) {
     String lUUID = UUID.randomUUID().toString();
     aContext.sink("pds:/rsk/" + lFilename, lUUID);
   }

   lResult = aContext.source("pds:/rsk/" + lFilename, String.class);

   INKFResponse response;
   response = aContext.createResponseFrom(lResult);
}


Not too complex is it ? We want to read a persisted file. If it doesn't exist yet we create it first. Is that then my technical tip ? No, there's a small caching problem with the above code. When the file does not exist yet, the result is not cached.


And small though that problem may be, it can add up over time if you do lots of creating. The problem is of course the sink statement. Since that changes the very resource we want to cache the result of the onSource request can not be cached. So here is the solution :


public void onSource(INKFRequestContext aContext) throws Exception {

    String lFilename = aContext.getThisRequest().getArgumentValue("filename");
    String lResult;

    if (!aContext.exists("pds:/rsk/" + lFilename) {
      String lUUID = UUID.randomUUID().toString();
      subrequest = aContext.createRequest("pds:/rsk/" + lFilename);
      subrequest.addPrimaryArgument(lUUID);
      subrequest.setVerb(INKFRequestReadOnly.VERB_SINK);
      subrequest.setHeader("exclude-dependencies",true);
      aContext.issueRequest(subrequest);
   }

   lResult = aContext.source("pds:/rsk/" + lFilename, String.class);

   INKFResponse response;
   response = aContext.createResponseFrom(lResult);
}


By setting the exclude-dependencies on the sink request, that request is ignored when determining the cachebility of the onSource.

Did you notice my smugness ?  The problem is of course the sink statement. Very nice Tom. Only ... the above still doesn't cache. Oops.
With both feet back on the ground, I called in the help of the caching ninja himself ... *drumroll* ... Tony Butterfield. I gave him no more than a Visualizer trace, he didn't need (nor want) the code. Obviously the age old use the force, read the source is no longer in effect.

He probably had a good laugh at my expense ... and then said ... good work on the sink, but the remaining problem is of course the exists statement.


The what ? The exists statement ? Here's the final code :


public void onSource(INKFRequestContext aContext) throws Exception {
   String lFilename = aContext.getThisRequest().getArgumentValue("filename");
   String lResult;

   INKFRequest subrequest = aContext.createRequest("pds:/rsk/" + lFilename);
   subrequest.setVerb(INKFRequestReadOnly.VERB_EXISTS);
   subrequest.setHeader("exclude-dependencies",true);
   Boolean lPDSExists = (Boolean)aContext.issueRequest(subrequest);

   if (! lPDSExists) {
     String lUUID = UUID.randomUUID().toString();
     subrequest = aContext.createRequest("pds:/rsk/" + lFilename);
     subrequest.addPrimaryArgument(lUUID);
     subrequest.setVerb(INKFRequestReadOnly.VERB_SINK);
     subrequest.setHeader("exclude-dependencies",true);
     aContext.issueRequest(subrequest);
   }

   lResult = aContext.source("pds:/rsk/" + lFilename, String.class);

   INKFResponse response;
   response = aContext.createResponseFrom(lResult);
}



Yes, the exists was the remaining problem. If the resource does not exist, it obviously starts out as false. Next we sink the resource that is linked to the exists ... and that result (the false) is no longer valid. Which also makes the result of the onSource uncacheable.

Once more 
exclude-dependencies comes to the rescue.

Now, before you start using this as your big trick, remember that it is important you
understand why and when you want to circumvent the default caching behaviour ! In the above case it may have brought a benefit, but now the code needs more documentation too.

Have a great week !


P.S. In case you think I enjoy punning and envision myself quite the funny guy ... here's a couple of the obvious puns I did not use :

- Code for cache.
- It's all about cache Baby, it's all about you and NetKernel.
- To cache or not to cache, that is the question !
- In Tony Butterfield we trust, all others must use cache.