Saturday, February 18, 2006

Up All Night with AFP

No, I didn't pull an all nighter and stay up writing AFP code. :) I can't remember the last time I pulled an all nighter coding. 3:00 AM is my limit nowadays and that's pretty rare.

Anyway, my Waking Up AFP blog entry got an immediate rise out of Chrisof at Prolib, the author of AFP. I kind of figured it would. :)

AFP has a lot of configuration options and of course, how long it stays up and running on the server is one of the things you can configure.

So, here's what Christof had to say about it:

The default configuration is to shut down an engine when it's been idle for 15 minutes or has processed 2000 hits (to avoid memory problems). You can change that in the afp.config file (or in the ControlCenter):

max-idle="900" max-uptime="0" max-hits="0"

max-uptime defines that an AFP engine stops when it has been running for the specified number of seconds, no matter how many hits it processed or how long it has been idle. These settings define how AFP shuts down engines.

A second set of parameter specifies how AFP deals with starting engines:

threads="4" min-threads="0" max-threads="4"

The default configuration tells AFP to start 4 engines when it starts up. On demand AFP launches up to a total of four engines (it starts with the maximum number), AFP monitors that the number of engines never goes down below zero (that is, all engines can terminate). If you change the min-threads value to "1", AFP always keeps one instance running. Together with the max-idle setting, this would cause AFP to restart the egine every 15 minutes, but always keep one available for fast response times. You can increase the max-threads value to increase reaction time for higher request rates. The recommended value is four times the number of processors on your machine. The best value depends on a number of factors and is best determined by experimenting.

There's a whole multi-threading infrastructure in AFP.

Thanks for setting me straight Christof!

Friday, February 17, 2006

Waking up AFP in the background

I’m in the final stages of the development of a commercial website that was built using AFP. I’ve been really pleased with how well AFP has worked for this site and its performance. Because AFP is VFP, obviously its data handling capabilities are superb. I’ve found this to fit in really well with AJAX style applications because typically server side scripting is handling data intensive operations.

One caveat to using any VFP technology for server side scripting is its load time. So, of course, this applies to AFP. If AFP hasn’t done anything in a while, it shuts down. That means that when you hit an AFP page, AFP has to be loaded. AFP loads the VFP runtime and this seems to be by far the biggest bottleneck in its startup time. So basically the amount of time it takes to load AFP is roughly equivalent to the amount of time it takes VFP to load, AFP then has to process the page the user navigated to and then lastly, the page is returned to the browser. The end result of all this is that the first time a user hits an AFP page on your server (when AFP isn’t already running) is slow.

I decided to deal with this by stealing a few techniques from my AJAX functions. It’s pretty simple really, in the onload event of non AFP page (which is my home page), make an XMLHTTP call to open a dummy .AFP page in the background. This starts AFP while the user is viewing the page. By the time they click on a link to an AFP page AFP is already up and running and then the performance is of course, snappy.
I always have trouble getting code to format in the blog, but here it goes.
First, in the body section of your page add onload=”LoadAFP()”. This code tells your browser to execute this function after the page has loaded.

Now, if you want to avoid an error, you need a LoadAFP function. You can place it in a .js file and simply reference the file, which I’d recommend if you’re going to do this in more than one page or you can place it in the heading section of your page. Here’s the code for that, sans the script tags which Blogger will eat.

function LoadAFP() {
var xmlhttp;
/*@cc_on
@if (@_jscript_version >= 5)
try {
xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (E) {
xmlhttp = false;
}
}
@else
xmlhttp = false;
@end @*/
if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
try {
xmlhttp = new XMLHttpRequest();
} catch (e) {
xmlhttp = false;
}
}
xmlhttp.open("GET", "http://www.f1tech.com/afploader.afp", true);
xmlhttp.send(null);
}

Basically this function just creates the xmlhttp object – which is complicated due to browser differences. In ie7 (currently in beta), it’ll be native to the browser like it is currently in modern Mozzilla based browsers, but it’ll be a long time before you can just count on it being present. Once you’ve got a reference to an xmlhttp object, the last two lines are one loads AFP in the background. Make sure you change the URL to something on your own server. Starting AFP on mine won’t help your performance. BTW, I didn’t include any code for afploader.afp because it can be any old AFP page. I didn’t test this, but I’d suspect it doesn’t even have to include and AFP script. AFP is invoked on the server whenever a request is made for a file with a .AFP extension.

I also played around with another variation of this that might be more appropriate if you're using AFP on your home page. Basically, the idea is to make a dummy homepage that just says something like "Server idle, loading website..." and then in your onload section just call a oneline javascript function that reads:

function LoadAFP() {
window.location="YourAFPHomePage.AFP"
}

This approach displays the server idle message for as long as necessary, then displays your home page. If AFP is already loaded it jumps to the homepage immediately.

Neither of these techniques take a lot of effort or are difficult to implement, but I think they can really make a difference for visitors to your website.

Thursday, February 02, 2006

To GMT or to not GMT

Toni and I are currently working on a project that has had as many as 9 developers working on it at one time, working from as many as four different locations, plus some developers also working from home. As a result, we've been doing a lot of work on VFE in recent months to make it more friendlier for team environment. One of the things we added to DBCX recently was the ability to write all of the metadata for a DBC out to an XML file and to load metadata from this XML file. This lets developers check in and check out individual DBCs and makes it easier for other developers to get their data dictionary changes without having to check in or check out the meta data for the entire project all at once. The project we're on currently has 47 DBCs, so you can imagine there's a lot of meta data as well.

Anyway, in working on this, I discovered that I needed to make sure that I properly dealt with different time zones. One of the offices is on West Coast time and well, Toni and I are likely to login from any number of time zones - and seeing as its February in Toledo right now, Hawaii Time sounds about perfect. So, in order to avoid any confusion related to timezones, I built the mechanisms for checking date and time of the changed metadata around GMT - Greenwich Mean Time. In a nutshell, in GMT it's always the same time everywhere in the world, no matter what time zone you're in - even if you're in Indiana or New Foundland. For more info on GMT, check this out.

I haven't done real well with posting code in the blog, so I put a file of the GMT related functions here.

There are 4 functions in this procedure file:
  • GMTDateTime() - which returns the current GMTDateTime. There's a Windows API call to get this.
  • GMTTimeDifference() - which returns the difference in seconds between the machine's local time and GMT. This function is used internally for the remaining functions.
  • GMTToLocal(ltDateTime) - which converts GMT a to its local equivalent.
  • LocalToGMT(ltDateTime) - which converts a local date & time to its GMT equivalent.
The code is commented pretty well, so I won't bore you with the details here.

This really got me thinking, should my applications be storing dates and times in GMT and then converting it to the current users local date and time for display purposes? It'd really depend on the application, but this is definitely something that I plan on giving somethought with my next application. Most of the time when we look at a date and time, we think of it in terms of our current locale, this could be a big issue in apps where the data comes from multiple locations and of course in web apps, where the users could be logging on at any time from any where.

So, I don't really have any guidelines or recommendations at this point for when GMT should or should not be used. If you have any, let me know. It's definitely something worth more thought.