You are currently browsing the category archive for the ‘Appliance’ category.
[Update 3/16/2009: see the post GLASS Beta Update: Cooking with GLASS (Preview) for the latest GLASS preview release. A new appliance is not yet available, so to use the new tools you should update to a new version of the GemTools Client and GLASS Server, using these instructions].
1.0Beta11 is based upon GLASS.230-dkh.164, see the 2.3 announcement for details.
If you are using an earlier version of the appliance, we suggest that you start using the 1.0beta11 appliance
The big news for 2.3 beta2 is that we’ve got support for the full Unicode character range. Previously we supported up to 16 bit characters with DoubleByteString. In 2.3, we’ve added the class QuadByteString for supporting up to 32 bit characters. There should be more information in the release notes for 2.3, but until the release notes are available, you can review the chapter on “Extended Character Set Support” in the 2.2 Release Notes.
The following bugs were fixed:
- bug39137 – ‘Magritte validation error (specifically for MARequiredError)’
- bug39246 – ‘URL can cause fastcgi infinite recursion and vm crash’
- bug39274 – ‘RRRssHandler>>handleRequest: ObjectLog support for debugging problems’
The appliance also includes some performance improvements for FastCGI.
Beta 2 is shipped with GLASS.230-dkh.155 and GemStone-jgf.291(both can be found in the GLASS project on GemSource). If you are using an external Squeak image, you should probably use the image and changes files that are shipped with the release:
- You can download the GemStone ‘GemTools one-click’ from http://seaside.gemstone.com/downloads.html [thanks Monty!].
- For the appliance you can download the GemStone one-click from the appliance itself by navigating to the downloads page in your browser (http://<appliance ip address>/downloads.html).
- For the standard (Linux or Mac) install, the image and changes can be found in $GEMSTONE/seaside/squeak_3.9 and the latest GCI library $GEMSTONE/lib/libgcsi64-230.so.
If you are using 1.0beta9, I encourage you to download and start using the new version of the appliance.
After a few hitches in our giddyup, we are pleased to announce the availability of the 1.0Beta9 GLASS appliance. The appliance is based upon GemStone/S 64 Version 2.3 Beta 1. We have published the download instructions (join our Beta mailing list) or you can send mail to request download instructions. To make sure that your hardware can run VMWare, double check the hardware requirements.
In the future, when I announce the availability of a new GLASS package in a GLASS Beta Update post we plan on making a new version of the appliance available as well.
In my post on Simple Persistence for Seaside, I claimed that with the recent enhancements to the Seaside framework in GLASS, it is perfectly okay to use an unprotected class variable to persist shared state. The use of an unprotected class variable will result in occasional commit conflicts, but when a conflict occurs, the framework does an abort and retries the original HTTP request.
So, just how occasional are these commit conflicts and what if I don’t like the idea of using anything uprotecteced. In the last two posts (Ready… and …Aim…), I introduced the tools that you need to answer the question for yourself. In the end it is the behavior of your application that matters the most.
As targets examples, I have written three very simple Seaside examples. Each of the applications is a variation on the theme of shared counters:
- WATally – counter using a class variable, expect retries due to commit conflicts.
- WARcTally – conflict free RcCounter, no commit conflicts.
- WASerial – use an object lock for the production of a unique value, expect retries due to busy/dirty lock.
With WATally, when a user clicks on the tally link, the current value of the Tally class variable is incremented and the result is stored back intoTally. This is a sure-fire formula for commit conflicts. The following diagram depicts the timeline for three overlapping tally requests:
Request 2 begins before Request 1 is finished, so its commit fails. After a short delay, the request is retried and succeeds. Request 3 also begins before Request 1 is finished, waits a bit and retries, but its retry attempt starts before Request 2 is finished, so the request fails again. Finally on the second retry, the commit for Request 3 succeeds.
If you run jcrawler against WaTally, you can expect to get a handful of Commit failures in the object log (http://localhost/seaside/tools/objectLogin an appliance). I found that using an interval of 1 is best for scaring up Commit failures. Click on the graphic below to see a full width log entry.
If you want to delve into the causes of the commit failure, you can inspect the object log using the following expression:
System abortTransaction. OTRemoteDebugger objectLog asArray inspect.
In this case you’ll find that the commits failed because of a Write-Write conflict on an ‘Association (#Tally->3864)’, which is expected.
It’s worth noting that jcrawler ran at about 12 requests/second for 2 minutes to generate the 38 ‘Commit failures’ and the retry limit was not exceeded. This is validation that ‘retrying requests on commit failure’ is a perfectly safe technique.
With WARcTally, when a user clicks on the tally link, a shared RcCounter instance is incremented. RcCounter is designed to allow concurrent, conflict free increments and decrements. The following diagram depicts the timeline for three overlapping HTTP requests.
Since RcCounters are desinged to be conflict free, each request completes without the need for retries.
If you run jcrawler against WaRcTally, you can expect an empty object log:).
Reduced conflict classes are still the best way to go, as they are designed to prevent commit failures and have undergone a ton of testing.
With WASerialNumber, when a user clicks on the tally link, an object lock is obtained on the shared instance of SerialNumber and the value instance variable is incremented and returned. If the lock is either changed or denied a WARetryHTTPRequest is signalled and the HTTP request is retried, much like the retry after a commit conflict for WATally. Object locks are not transactional, so an object lock can be acquired in the middle of a transaction. In this particular example, the lock (once acquired) is kept for the duration of the transaction.
The following diagram depicts the timeline for three overlapping HTTP requests:
Shortly after the processing for Request 1 begins, the SerialNumber object lock is acquired and when Request 1 finishes processing the lock is released.
Request 2 makes its first attempt to acquire the lock, while the lock is held by Request 1, so the lock request is denied. Request 2 signals a WARetryHTTPReqeuest. On the second retry attempt, Request 2 successfully acquires the lock and completes normally.
Request 3 makes its first attempt to acquire the lock after the lock is released by Request 1, so the lock is granted, however, since the transaction for Requst 3 started during the transaction for Request 1 and the SerialNumber instance is dirtied (the value instance variable has a new value), the lock is granted, but with a changed status. In a generic GemStone/S application, an abort would be performed and processing would continue, however, in GLASS/Seaside aborts are not allowed, so a changed lock is treated the same as a denied lock – a WARetryHTTPReqeuest is signalled. On the second attempt to acquire the lock the request is denied, because the lock is held by Request 2. A WARetryHTTPReqeuest is signalled again. Finally, on the second retry, the the lock is granted and the request is completed.
The GLASS/Seaside framework drops an entry in the object log whenever a WARetryHTTPReqeuest is signalled, so you can see the frequency of failed lock attempts. Click in the following image to see the full width log.
If you look closely at the full-eidth image, you will see the two different kinds of ‘Lock not acquired’ messages. ‘SerialNumber lock changed’ and ‘SerialNumber lock denied.’
jcrawler ran at about 10 requests/second for 2 minutes to generate the 72 ‘Lock not acquired’ entries.
Object locking as a technique for avoiding commit conflicts shares the ‘retry on failure’ model of WATally, so it isn’t necessarily superior to ‘retry on commit failure’. It is a superior technique, if you need to protect logical updates where a physical conflict cannot be guaranteed (i.e., updates to different portions of an object graph).
It certainly looks like the Simple Persistence model of retrying a request on commit failure will stand up under a moderate load. 10 requests/second without retry failures is a pretty good clip. In a real web site, the potential for conflicts is much lower than in these examples since most web page hits are read only, so you can expect to withstand an even higher overall request rate without too much trouble.
It is still a good idea to use reduced conflict classes or object locks in places where you know that concurrent updates can occur, but I think is important to realize that you you don’t have to protect every shared variable from concurrent updates.
Once you’ve fixed jcrawler so that it can follow dynamic URLs like those used in Seaside, you are ready to aim it at a Seaside application. In this post I’ll give you some pointers for getting started with jcrawler.
Out of the box, jcrawler is written to be run in the jcrawler/dist directory. There are relative paths in the run.sh shell script. That isn’t too convenient, so here’s a bash script that lets you run jcrawler from anywhere:
#!/bin/bash export JAVA_HOME=<path to java> export JCRAWLER_HOME=<path to jcrawler> $JAVA_HOME/bin/java -cp "$JCRAWLER_HOME/:\ $JCRAWLER_HOME/lib/log4j.jar:\ $JCRAWLER_HOME/lib/commons-logging.jar:\ $JCRAWLER_HOME/lib/commons-httpclient.jar:\ $JCRAWLER_HOME/lib/commons-digester.jar:\ $JCRAWLER_HOME/lib/commons-collections.jar:\ $JCRAWLER_HOME/lib/commons-beanutils.jar:\ $JCRAWLER_HOME/dist/jcrawler.jar:\ $JCRAWLER_HOME/lib/htmlparser.jar" com.jcrawler.Main
When you run jcrawler, it expects there to be a crawlerConfig.xml file in a local conf directory (./conf/crawlerConfig.xml). The following is one that I have used for testing against an appliance running at 10.80.21.64 on our internal network. I’ve supplied 4 starting URLs, one for each of the GemStone Examples (randomError, rcTally, tally and serial):
<!-- Interval (in milliseconds) to invoke a crawl thread. There is an HTTP hit every millisecond. --> <interval>250</interval> <!-- Interval (in milliseconds) to invoke a monitor thread. Monitor adds new entry in the monitor.log every milliseconds --> <monitorInterval>6000</monitorInterval> <!-- HTTP connection timeout in milliseconds --> <connectionTimeout>30000</connectionTimeout> <!-- Headers to be used by the http client crawler --> <headers> <header name="User-Agent">Mozilla</header> <header name="Cache-Control">no-cache</header> <header name="Accept-Language">en-us</header> </headers> <!-- URLs to start crawling from --> <crawl-urls> <url>http://10.80.21.64/seaside/examples/GemStone/rcTally/ </url> <url>http://10.80.21.64/seaside/examples/GemStone/serial/ </url> <url>http://10.80.21.64/seaside/examples/GemStone/tally/ </url> <url>http://10.80.21.64/seaside/examples/GemStone/randomError/ </url> </crawl-urls> <!-- URL patterns (regexps!!!) to allow or deny set of URLs permission=true - these patterns are allowed (anything else is denied) permission=false - these patterns are denied (anything else is allowed) --> <url-patterns permission="true"> <pattern>.*?10.80.21.64.*</pattern> </url-patterns> </settings>
With an interval of 250, jcrawler will run at about 4 requests/second which is fast enough to get started. If you don’t see fireworks at this rate, you can set the interval to zero and let jcrawler fire at will. To really hammer an application you can launch multiple instances of jcrawler.
Here’s a sample object log from one of my runs:
Notice that the report is dominated by entries labeled ‘Lock not acquired – retrying’. A glance at the full width log will show that the retry is due to a ‘Session lock denied: 2075’. A session lock is denied (and the request is retried) if two requests for the same session are received at the same time. This is not surprising given the fact that jcrawler uses a FIFO to store the URLs it scrapes from a page – almost every URL on a single page will have the same session key. When you see errors like this showing up in the object log, you at least know that jcrawler is firing simultaneous requests at Seaside.
As a final note, you should set deployment mode to true (using the Configuration Editor) before pointing jcrawler at your application. If you don’t, you are guaranteed to get some fireworks. While you’re in the Configuration Editor, take a look at the field for setting the Root Component. If the clear link is pressed, the root component for that application is wiped out. Until a new root component is set you will get internal server malfunctions, whenever the WADispatcher tries to launch a new instance of the application. If you don’t set deployment mode to true, jcrawler will eventually find its way into the Configuration Editor and it will eventually hit the clear link.
You are now ready to launch jcrawler at the WATally application and see how our Simple Persistence example fares under load.
Before we point jcrawler at a Seaside application I would like to talk about what you should expect.
To start with, jcrawler is like a bull in a china shop. The algorithm jcrawler uses is not very deterministic nor is it discriminating, but it is thorough, relentless and highly parallel. Given an an initial set of URLs, jcrawler traverses each page and adds the links it finds to its list. Every so often, jcrawler creates a new thread to process another URL from the list. We can depend upon jcrawler to rattle every piece of china in an application and it will rattle more than one piece at a time, so we’d better be ready to deal with wreckage.
Jcrawler will help make your application bullet proof, but at potentially 15 errors/second spread across several vms, there can be a lot of wreckage to sift through.
I added an object log to GLASS a couple of weeks ago and over the last couple of days, I’ve added a Seaside application for viewing and manipulating the object log. Take look at a sample log (my blog is wide-image challenged). It’s not the purtiest page this side of the Mississippi (I am web-design challenged:), but it does the job.
In the object log, the entries labeled ‘– continuation –, represent object log entries that can be debugged via the ‘Debug’ button in the GemStone/S Transcript Window. If you take a peek at the pid column, you will notice that the log entries were generated by two different gems. There are three gems serving HTTP requests in the appliance.
The upshot is that after letting jcrawler hammer on your application, not only do you get an overview of the problems uncovered during the run, but you can open a debugger and investigate the issues that resulted in walkbacks.
I generated the sample object log by manually playing with the randomError application (http://localhost/seaside/examples/GemStone/randomError in the appliance) found in the GemStone Examples project. This little gem generates a simple log entry (‘random error’) or walkback (‘– continuation –‘) 12% of the time. You can also generate different kinds of errors by poking the links in the Error tab of the alltests application (http://localhost/seaside/tests/alltests in the appliance).
If you want to play with the object log, load up the latest version of the GLASS package (GLASS-dkh.103 in the GLASS project – it will also load the GemStone Examples). Poke around in the randErrror application until you get an error then head on over to the object log (http://localhost/seaside/tools/objectLog in the appliance). You can also try the remote debugger from your development image.
Next up we’ll talk a little bit about configuring jcrawler.
In the past, I had talked about how to add persistence to Seaside applications using GLASS, but up until recently, I hadn’t supplied any concrete examples. A month or so ago, the stars aligned, and I took the opportunity to start writing some Seaside examples for GLASS. I figured I would start with a simple example that ignored concurrency issues and then over a series of examples, I’d illustrate the techniques for navigating the treacherous waters of transaction conflicts. I even monkeyed around with jcrawler, so that I’d have a tool that could be used to expose concurrency flaws in the examples.
For the simple persistence example, I decide to copy WACounter, remove the count instance variable and replace it with a class variable reference (Tally) – the simplest example of persistence possible (see WATally in GemStone Examples).
No object lock, no reduced conflict class so look out boys, transaction conflicts are on the menu tonight.
Did I mention that the stars had aligned?
As I was working out the details of an object locking example based on a problem posed by Ken Tries, I realized that when an object lock is denied, the simplest answer is to just retry the HTTP request.
The standard pattern for dealing with a denied object lock in GemStone/S is to wait a bit, abort and attempt to acquire the lock again. If you recall in GLASS, when an HTTP request comes in to a server, we do a beginTransaction (equivalent to an abort), process the request and then do a commit. So, when an object lock is denied while processing a request, we throw an exception, abort the transaction, delay for a bit and retry the request. Each request is handled in its own thread, so while the request is delayed, other requests can be processed by the server. A nice, clean solution that fits very well within the GemStone/Seaside framework.
As I was coding up the solution for object locks (see WASerialNumber and SerialNumber in GemStone Examples) I realized that the same technique (wait a bit and retry the HTTP request) would be the perfect answer for handling transaction conflicts.
So to bring a long story to an end, what started out as a poor example for doing persistence in GLASS has turned into a perfectly good example for doing persistence in GLASS.
All of the rigamarole about needing to avoid transaction conflicts goes right out the window! For high traffic sites or for potentially overlapping requests (i.e., relatively long request processing times), it is still worth using Reduced Conflict classes or object locks to minimize the chance for transaction conflicts. In most cases, though, a simple class variable or global reference will do the trick.
This is the first post in a series of articles that will be covering practical topics for developers working with GLASS. For simplicity’s sake all examples in these articles will be written as if you are using the appliance, however, if you are using a Linux install of GLASS, you should be able to adapt the examples to your specific installation. If you want to delve into more detail you should read the GemStone 101 series of articles or dive into our most excellent documentation.
To start things off, I’d like to drive home the notion of shared, persistent session state for Seaside.
We’ll start with a graphic example where we’ll kill off the web server gems in the middle of a session, restart the gems and observe that the user experience can continue uninterrupted.
To give it a try:
- Bring up the counter example in your browser (http://localhost/seaside/examples/counter) and click on the ++ link a couple of times.
- Shut down the Seaside web server gems (using the GLASS Appliance>>GLASS Components>>Gemstone – Gems>>Stop menu item).
- Click on the ++ link after shutting down the gems and you should get a server error – not surprising.
- Restart the server gems (using the GLASS Appliance>>GLASS Components>>Gemstone – Gems>>Start menu item).
- Press the back button in you browser to bring back the cached browser page.
- Finally, click on ++ link and you will see the the value continues to increment as if nothing had happened.
In GLASS, session state is persistent – cached in the Shared Page Cache (SPC) and stored on disk – along with application data. Being able to share session state and application data via the SPC means that multiple web server vms can service HTTP requests without having to account for session affinity. It also means that web server vms can be brought on and off line as needed without interrupting ongoing sessions.
Probably the most important point is that this is done without requiring any extra work on the part of the developer and it is done very efficiently.
Version 1.0beta6 of the appliance is rolling off the assembly line and that new software smell is once again wafting through the hallways of our Beaverton office. If you are using an appliance that is older than 1.0beta5, then you should contact us to get download instructions for 1.0beta6.
On the development front, I am busy getting a port of SourceSource 2 running on GemStone. SourceSource 2 is Philippe Marschall’s port of SqueakSource to Seaside2.8 and Magritte. When I’m done I think that this will be a good example of what types of things need to be done to port a Squeak Seaside app to GemStone.
Oh, and don’t forget to sign up for our GLASS Beta mailing list.
[Update 3/16/2009: see the post GLASS Beta Update: Cooking with GLASS (Preview) for the latest GLASS preview release. If you update your GemTools Client and GLASS Server as suggested see the Terse Guide to the (new) GLASS Tools for documentation that matches the new tool set].
So you’ve been working with Seaside in Squeak for a little bit and you’ve gotten to the point where you have started to think about persistence. You’ve heard about GLASS, you’ve got 64 bit hardware that’ll run VMWare and you’ve downloaded a copy of the appliance. You’ve clicked on the ‘Run Squeak’ menu item or you’ve executed the Smalltalk expression ‘GsLoginWindow open’ in a Squeak workspace, you’ve got Los Lobos’ ‘Beautiful Maria of My Soul’ queued up and you’re ready to rumba.
We’ll take a quick tour of the tools that will be available with version 2.2.4 to get your Cuban Motion in gear. Even if you’ve been using GLASS for awhile, it’s probably worth skimming this post since there are likely some new capabilities that you’ve been anxiously awaiting.
If you’re new to Squeak and Smalltalk, then you should check out the most excellent Squeak by Example or Steve Wessel’s excellent Squeak Tutorial. If you are new to Seaside, you should check out the Seaside Tutorial from Hasso-Plattner-Institut. If you’re going to do development in GemStone/S, then you should read the articles in GemStone 101.
Here’s a set of links for quick navigation to specific sections:
The first thing you need to do is to establish a GemStone session. With the GemStone/S Login window, you specify the host name (or ip address) where the stone is running, the name of the stone, the host name (or ip address) where you want the gem to run, and the name or port number of netldi. For the Web Edition (i.e., free version), remote gems are not permitted, so the host name for the stone and the host name for the gem will always be the same.
When you press the “Login” button the Squeak image contacts the netldi which launches a gem on the stone’s host. Upon successful launching of the gem, the GemStone/S Transcript window is opened.
The gem creates a log file in the home directory (typically) of the user that owns the gem process (in the appliance that would be /home/glass). If the gem process ever exits unexpectedly, you can check in the log file for error messages.
The most common reason for a gem to exit unexpectedly is that it ran out of memory. If the gem runs out of memory, a fairly detailed report is dumped to the gem log. If there are no errors when the gem exits it will delete it’s log file. If you do run out of memory, you can bump up the size of the GEM_TEMPOBJ_CACHE_SIZE in the gem.conf (on the appliance it’s found in /opt/gemstone/product/seaside/data).
The GemStone/S Transcript window is the control point for interacting with your GemStone session. For all of the GemStone tools, we are using Squeak as a windowing client. You want to remember that there is no interesting Smalltalk state being kept in your Squeak image, other than what is necessary for displaying the windows.
All of the GemStone tool windows have bland grey color and a “G/S[<GCI#>]” in the title bar to remind you that you’re in a GemStone window. You can open multiple sessions (gems) from a single Squeak image, so the GCI# helps you tell which session the window is operating against. Since the GCI library is not thread safe (i.e., only a single GCI call may be made at any one time), running multiple sessions from a single Squeak image is of limited utility.
The row of buttons across the top of window, give you quick access to the most commonly used windows and functions. Each window/function is covered in its own section:
The text pane in the GemStone/S Transcript window is actually a workspace and not a transcript. This window is slated to be reimplemented in OmniBrowser and we’ll fix the name then:). When you do an accept in this window, the text is stored in a class variable on the Squeak-side, so the text can be preserved across session boundaries. This is the one piece of state that would make it worth saving your Squeak image.
While we’re talking about image saving, it used to be that when you saved the Squeak image, all GemStone sessions were unilateraly destroyed rendering all of your GemStone windows inoperable. With the tools being released in conjunction with version 2.2.4, it is safe to save your Squeak image with GemStone windows open. When you restart a saved image, all of the open GemStone windows will be closed.
When you close the GemStone/S Transcript window (or press the Logout button), the GemStone session will be terminated (i.e., the gem process will exit) and all of the GemStone windows in the Squeak image associated with the session will be closed.
Back in December, while I was watching Avi write the Monticello tools in OmniBrowser, I saw him use some keyboard shortcuts that weren’t on the text pane menu. He was browsing classes and bringing up senders and implementors windows with a couple of key presses – things that I had been struggling to do without shortcuts.
In most GUIs, a program’s keyboard shortcuts are discoverable by browsing the program’s menus – the shortcut is indicated in the menu choice.
Without going into the pros and cons, I decided to keep the menus short and follow the Squeak/OmniBrowser example. The following keyboard shortcuts are supported in all of the GemStone text panes whether they show up in a menu or not:
- CTL-b browse selected class
- CTL-N references for selected class
- CTL-n senders of selected selector
- CTL-m implementors of selected selector
- CTL-E methods containing selected string
- CTL-i inspect it
- CTL-p print it
- CTL-d do it
In workspaces, the evaluation context for CTL-i, CTL-p, and CTL-d, is not defined, which means that you can’t use ‘self’ in workspace expressions. In code browsers the evaluation context is the selected class (‘self’ is the class), in debuggers the evaluation context is the message receiver, and in inspectors the evaluation context is the inspected object (you have to select a field in the inspector to set the inspected object).
I am going to write separate post to cover Monticello in GLASS. Suffice it to say that OmniBrowser-based Monticello tools closely parallel their Morphic-based cousins with the exception of a couple of functions that were not used a whole lot. If you find what you consider an important piece of functionality missing, by all means let me know via a comment on this blog, or join the news group described in the Bug Reports section.
For those of you who have been using the Morhpic-based Monticello tools. You will be happy to know that the arcane rigamarole that you used to have to go through after loading a package is no longer necessary. Changes to the code in a package will cause the package to be marked dirty, however, you may have to refresh a window to see the changes.
I have not implemented a window to window update mechanism, yet, so changes made in one window will not automatically show up in another window. Getting window updates to propogate is high on my priority list.
When you press the Browse… button, you are prompted for a ‘Class name fragment’ (no need to worry about capitalization or including wildcard characters). If the fragment resolves to a single class, a System Browser is opened on that class. If the fragment resolves to multiple classes, you are given a list of classes from which to choose your desired class.
From the System Browser, you can navigate to the full complement of windows available in OB-Standard.
You might notice that in the class category pane, there is no ‘add category’ menu item available. GemStone manages it’s classes slightly differently than Squeak and the Class categories are derived from the classes. So when you create a class, you create the new category along with the class.
When you press the Find Method… button you are prompted for a ‘method fragment’ (no need to worry about capitalization or wildcard characters and multi-keyword selector fragments like ‘at:put’ are fine). If the fragment resolves to a single selector, then an Implementors window is opened, otherwise you are prompted to choose the selector of interest from a list.
The Implementors, Senders, and Variables windows are chasing browsers. The upper right pane contains a list of the messages sent by the method selected in the upper left pane. If you were to click lastValue in the upper right pane, you’d get a scroll bar below the selection lists, the left pane would be replaced by the messages pane and the upper tight pane would contain a list of implementors of #lastValue. You can scroll back to the left to see the original implementors left, or continue walking panes to the right. Chasing browsers are a little disconcerting to use, but once you realize how much the window clutter is reduced by using them, you will grow to like them.
Occasionally, when you accept a method in the Implementors, Senders, and Variables windows, the method text will appear to revert back to it’s original value. If you reselect the method, you will see that the source you accepted has actually been saved. There are a handful of these update bugs that I will be hunting down and eradicating as time goes by.
The Test Runner is one of the last remaing Morphic windows in the GemStone tool set. When you press the Test Runner button be prepared to wait a bit while a ton of data is transferred from the gem to the Squeak image. Updating after making a selection can take a bit as well, but I’d rather have a slow Test Runner window than none at all.
Not all of the functions in the Test Runner are functional for the GemStone tools, but ‘Run Selected’ works and if you get errors or test failures, clicking on the failure will bring up a GemStone debugger. Note also that ‘run test’ menu items can be found in the category, class, protocol and method panes of the code browsers.
When you look at the debugger you immediately notice that the receiver and context inspector panes are missing! Until very recently it was difficult to get OmniBrowser to lay out a window configured like a traditional debugger. Lukas has been busy working on OB-Tools which implements a number of the Squeak windows using OmniBrowser and I think he may have a version of the debugger with integrated inspectors. I last merged with OB-Tools-lr.13 and Lukas is up to Ob-Tools-lr.19. Add one more item to my todo list.
To get around the lack of integrated inspectors, I added an ‘inspect context’ button that brings up an inspector that gives you combined view of the context and the receiver. The context inspector is slaved to the debugger, so that as you select different contexts the inspector updates its view to reflect the state of the selected context. I like the extra screen real estate afforded by the context inspector and dislike the fact that I am a couple of clicks farther away from seeing important information.
To facilitate Bug Reports, I’ve added a ‘copy stack’ menu that prints up a stack report including receiver and context info for each stack element.
GemStone/S supports breakpoints, so it isn’t always necessary to edit a method to get the debugger to stop at an interesting point. The definition pane menu in the code browsers and debugger has a ‘set breakpoint’ item that will set a breakpoint at the selected point in a method. For a method that has a breakpoint set, an additional menu item, ‘clear method breakpoints’, shows up and allows you to clear all of the breakpoints in the selected method. If a breakpoint is set on any method in the system, a ‘clear ALL breakpoints’ method shows up on all of the definition pane menus and will clear all the breakpoints in your session when selected.
A breakpoint browser is on the drawing board that will allow for the individual control of breakpoints, including disable/enable selected breakpoints.
Breakpoints are session-based and are associated with a particular instance of a method. If the method changes by either code changes on your part or the method is changed via an update via a commit or abort, then the previously set breakpoints aren’t active on the new instance of the method.
Like the Implementors, Senders and Variables windows, the Inspector window is a chasing window. When you click on a field in the upper left inspector pane, the inspector for the object associated with the selection is shown in the upper right pane. The context for bottom workspace pane is derived from the selected object (not the selected field). Selecting a field in the upper right pane will bring up the scroll bar for the selection lists, sliding the upper right pane to the left, and showing the object inspector for the newly selected field in the upper right pane.
The example below happens to be a context inspector associated with the debugger window in the Debugger example.
Selecting the currentRequest field in the above example, shows an inspector on the instance of WARequest in the upper right pane. A field is selected for the instance of WAExpirySession in the upper left pane so a CTL-p in the bottom pane on escapeContinuation will be evaluated in the context of the WAExpirySession instance.
If you type an expression in the bottom pane and hit CTL-s, the value of the selected field will be set to the result of the expression (Liliana, you should be happy now:).
The Abort and Commit buttons in the GemStone/S Transcript window allow you to manually abort or commit your work.
When you press the Commit button it is the moral equivalent of saving your image in Squeak. The Abort button is the moral equivalent of quitting your Squeak image and restarting from your latest saved copy.
When you abort or commit, you are updated to the latest view of the repository. With an abort, all changes to persistent objects are discarded before the update. With a commit, your changes to persistent objects are incorporated into the latest view of the repository. For more information of transactions, take a look at the posts in GemStone 101.
Inadvertant use of the Abort button can be disastrous, so you are prompted before the abort is performed.
As discussed in GemStone 101: Transaction Conflicts, if during your interactive session you have executed code that has made changes to an object that was also changed by another session since your last abort, you will get a transaction conflict if you attempt to commit. If the commit fails due to transaction conflicts, you will see the following notification:
No matter which option you choose, you will ultimately have to abort your session before being allowed to commit again. Transaction conflicts do not happen very often during development, especially if you are working by yourself;).
In a group, a transaction conflict could occur if two developers made changes to the same class at the same time. For group development it makes a lot of sense to give each developer their own appliance (or userID) and use Monticello to share your code.
If you are doing development against a stone where the Seaside application is being hit by other users or processes (i.e., siege or WAPT) and you are actively updating shared data structures, you could very easily hit a transaction conflict.
Choosing to inspect transaction conflicts will bring up an inspector on the transacation conflicts Dictionary. Take a look at the comment in System class>>transactionConflicts for more details on the information contained in the Dictionary.
To create the above transaction conflict, I opened two GemStone/S Transcript windows, evaluated the expression ‘UserGlobals at:#Shared_TEST put: Object new’ in one workspace and pressed Commit button. This defined a new association in the UserGlobals SymbolDictionary. I pressed the Abort button in the other session’s transcript window and evaluated the same expression it it’s workspace and pressed the Commit button. Then in original transcript window (without pressing the Abort button first), I evaluated the expression again and pressed the Commit button, which gave me the transaction conflict. Knowing which object(s) are involved in the conflict should give you a pretty good clue as to where the problem might be located.
I am afraid that I may have broken the functionality of the Auto commit checkbox in the GemStone/S Transcript windows when I moved the browsers and Monticello to OmniBrowser. Given the frequency with which I press the Commit button, I will probably fix this feature in a future release, if noone else beats me to it:).
If you just loaded some new code into the GemStone repository, or finished doing a bit of development, the easiest way to test out the new code is launch Hyper directly from your session, so that you can bring up the Debugger, if you encounter a problem.
The Hyper button prompts for a port number and launches a Hyper instance that is listening on the specified port number. You can then hit that port from your browser using a host name or ip address (i.e., http://172.16.172.134:9765/seaside or http://glass:9765/seaside or http://localhost:9765/seaside).
In older versions of GLASS, the Hyper-based web server required an exact match between the name of the host that you used to launch Hyper and the name of the host in the URL, which caused some unnecessary difficulties in connecting to the Hyper server.
When you launch Hyper, we block the UI process in Squeak. To interrupt the Hyper thread, you can hit Alt-.. Rember that for every HTTP request that comes in, the gem performs an abort, processes the request, then performs a commit. If you were trying to write code while this was going on, you’d easily lose chunks of work without warning.
If you want to do development and handle debuggable HTTP requests at the same time, the best solution is to fire off one Squeak image that is dedicated to running Hyper and use a second Squeak image to do development. When you’re done writing a batch of code, you can commit and the gem running Hyper will see the changes after the next request comes in.
If you hit a problem, you can use the debugger in the Hyper image to figure things out, just remember to commit your changes in the Hyper image before proceeding or restarting the Hyper process. Back in your development image, you’ll want to do an abort to pick up the changes that you made in the Hyper image. Breakpoints are session-specific, so you will need to set any breakpoints in your Hyper image, before launching Hyper.
If you find yourself trying to debug a problem that only shows up in FastCGI, you can arrange to start one or more Squeak images running FastCGI. For example, if you are using the appliance you could stop the threee gems that are servicing FastCGI requests and start three Squeak images to serve the FastCGI requests. Execute ‘FSSeasideHandler startUp: 9001’ in a GemStone workspace in the first image, ‘FSSeasideHandler startUp: 9002’ in the second, and ‘FSSeasideHandler startUp: 9003’ in the third. Alternatively, we’ve defined an Apache virtual host for each FastCGI port, so you can start just one Squeak image on FastCGI port 9001 (‘FSSeasideHandler startUp: 9001’) and then hit http://glass:8081/seaside with your browser. Ports 8081, 8082, and 8083 bypass the Apache load balancer and route HTTP requests directly to the FastCGI ports 9001, 9002, or 9003 respectively.
When the Logout button is pressed, the session is terminated and all windows associated with that session are closed, including the GemStone/S Transcript window.
With release of GemStone/S 64 version 2.2.4, the tools are finally of Beta quality. I’ve mentioned a couple of the known problems in this post, but my philosophy on bug reports is that you can’t have too many of them – don’t assume that we’ve seen the obvious problems, if you think it is a bug let us know.
To report bugs, sign up for our GLASS Beta mailing list and send a message to the list detailing the problem you’ve seen.
Even if you don’t have a bug report, I encourage to sign up for the GLASS mailing list. Seaside specific questions should still be directed to the Seaside mailing list. GemStone-specific questions can also be routed to the GemStone/S customer forum, most of our customers hang out there and are always willing to help folks that are new to GemStone/S.