I'll assume you've already installed Apache and now want to install Gemstone behind it as a Seaside server. Let's install a few things that we're going to need later, just to get the dependencies out of the way. Login to your server/workstation as an admin user, someone who can sudo.

Edit each of these scripts and change the line RUNASUSER=USER to RUNASUSER=glass and change the first line to #!/bin/bash instead of #/bin/sh as the Gemstone scripts need bash and Ubuntu changed the bin/sh link to point to dash instead of bash which won't work.

Install the init scripts. There's a shorter way to write these, but it will fit better on the blog if I do each one separately.

Edit the connection to point at localhost and login to Gemstone and open Monticello; open the MetacelloRepository; load either ConfigurationOfSeaside28 or ConfigurationOfSeaside30. I'm still on 2.8 so that's what I'm loading. If you're going to load 3.0, you'll need to edit the gs_fastcgi script accordingly as it's built to startup 2.8. Just change the DAEMON line to runSeasideGems30 instead of runSeasideGems.

Click the admin button on the gem launcher and check commit on almost out of memory option (just in case loading anything takes up too much temp space), then run ConfigurationOfSeaside28 load in the workspace. Once Seaside is loaded, we can continue and start up the Seaside gems.

sudo /etc/init.d/gs_fastcgi start

Next we need to setup Apache to be able to use FastCGI and enable a few modules we'll need and will need to first build the FastCGI module.

Hopefully you've gotten no errors at this point and you can navigate to http://yourMachineName/seaside/config and see that everything is working. Gemstone is now installed as a service, as is netldi and the Seaside FastCGI gems, and they'll start up automatically when the machine starts.

I'm not thrilled with running the Seaside gems this way because if they die nothing will restart them. I'll be following up later with a post on running the Seaside gems and maintenance gem under Monit which will ensure they're restarted should a gem crash for any reason. Gemstone itself and netldi I'm not worried about and this approach should work fine.

Since I did this on my workstation which already had apache installed as well as other things I run, I may have missed a dependency or two that I already had installed and didn't notice. If the above procedure doesn't work for you for any reason, please let me know what I overlooked.

Just a quick post to document some knowledge for myself and for anyone using Gemstone on a remote server like SliceHost or my preference Linode and trying to run GemTools locally through a ssh tunnel. It's slow, very slow, several seconds per mouse click. OmniBrowser is just to chatty. Fortunately Linux has a better way to do it: X11Forwarding. Run the GemTools client on the remote server and forward the UI for just that app to your workstation.

Now, if you have a mostly Windows background like I do, this might be something new to you, it certainly was to me. I'd kind of heard of it, but didn't realize what it was until today after I got it working. Just one more frakking cool thing Linux can do, much nicer than VNC/Remote Desktop because it means you don't have to install any window manager and the other hundred dependencies that go with it on the server. Every piece of software installed on a remote server is a piece of software that needs updated and/or could be hacked or make the next upgrade not go smoothly, so the less stuff installed on a server the better as far as I'm concerned.

I happen to be running the latest 64bit Ubuntu 10.4 LTS on a Linode server, so if you're running something else the steps might be slightly different. To prep the server, which I'm assuming is a headless server managed via ssh, you'll only need to install two packages. One to enable the X11 forwarding and one to install a library that the Squeak VM needs for its UI that's not installed by default on a headless server.

sudo aptitude install xauth libgl1-mesa-dev ia32-libs

You'll also need to enable X11Forwarding in /etc/ssh/sshd_config by ensuring this line exists.

And everything is ready to go. Now ssh in again but this time with forwarding and compression enabled.

ssh -X -C glass@serverName

Now any graphical program started on the server from this session, will run on the server, but its UI will display as a window on the client as if it were running directly on the client. Now fire up GemTools on the server...

cd GemTools-1.0-beta.8-244x.app
./GemTools.sh

And GemTools will start up and it'll appear to run locally, but it's actually running remotely which means OmniBrowser can be as chatty as it likes, it's all runnning from localhost from its point of view. The X display, which is built to do this much better, is running on your machine. Now GemTools will run fast enough that you could actually develop directly in Gemstone if you like. Not that I actually would, Pharo has much better tool support.

I think this will be the first of a run of posts about Gemstone, there's a lot to learn when switching dialects. I can tell you this, well tested code ports easier, so apparently I've got a lot of tests to write that I probably should have written from the start. Oh well, live and learn.

Forking a thread in Smalltalk is easy, wrap something in a block and call fork. It's so easy that you can easily become fork happy and get yourself into trouble by launching too may processes. About 6 months ago, my excessive background forking in a Seaside web app finally starting hurting; I'd have images that seemed to lock up for no reason using 100% CPU and they'd get killed by monitoring processes causing lost sessions. There was a reason; the process scheduler in Squeak/Pharo just isn't built to handle a crazy amount of threads and everything will slow to a crawl if you launch too many.

I had a search result page in Seaside that launched about 10 background threads for every page render and then the page would poll for the results of those computations, collect up any results found, and AJAX them into the page. Each one needs to run in its own thread because any one of them may hang up and take upwards of 30 seconds to finish its work even though the average time would be under a second. I don't want all the results being stalled waiting for the one slow result, so it made sense to have each on its own thread. This worked for quite a while with nothing but simple forking, but eventually, the load rose to the point that I needed a thread pool so I could limit the number of threads actually doing the work to a reasonable amount. So, let's write a thread pool.

First we'll need a unit of work to put on the thread, similar to a block or a future. Something we can return right away when an item is queued that can be checked for a result or used as a future result. We'll start by declaring a worker class with a few instance variables I know I'll need. A block for the actual work to be done, an expiration time to know if the work still needs done, a value cache to avoid doing the work more than once, a lock to block a calling thread treating the worker as a future value, and an error in case of failure to store the exception to be re-thrown on the main thread.

I'll also want a few constructors for creating them, one that just takes a block, and one that takes a block and an expiration time. For my app, if I don't have results within a certain amount of time, I just don't care anymore, so I'd rather have the work item expire and skip the work.

Now, since this is for use in a thread pool, I'll want a non-blocking method of forcing evaluation of the work so the thread worker isn't blocked. So if the work hasn't expired, evaluate the block and store any errors, then signal the Semaphore so any waiting clients are unblocked.

I'll also want a possibly blocking value method for retrieving the results of the work. If you call this right away, then it'll act like a future and block the caller until the queue has had time to process it using the evaluate method above.

But if you want to poll for a result, we'll need a method to see if the work has been done yet. We can do this by checking the state of the Semaphore; the worker has a value only after the Semaphore has been signaled.

ThreadWorker>>hasValue
^ lock isSignaled

That's all we need for the worker. Now we need a queue to make use of it. So we'll declare the class with some necessary instance variables and initialize them to some reasonable defaults along with some accessors to adjust the pool sizes. Now, since a thread pool is generally, by nature, something you only want one of (there are always exceptions, but I prefer simplicity) then we'll just rely on Smalltalk itself to ensure only one pool by making all of the pool methods class methods and the ThreadPool the only instance. I'll use a shared queue to handle the details of locking to ensure the workers share the pool of work safely.

Once you have a pool, you need to manage how many threads are actually in it and have it adjust to adapt to the workload. There are two main questions we need to ask ourselves to do this: are there enough threads or are there too many threads given the current workload. Let's answer those questions.

We also need a method for a worker to grab a queued work item and work it, and we don't ever want this to error out killing a worker thread since the worker thread should trap any error and re-throw them to the queuing thread. But just to be safe, we'll wrap it.

Now that workers have something to do, we'll need to be able to start and stop worker threads in order to increase or decrease the working thread count. Once a worker is started, we'll want it to simply work forever and the shared queue will handle blocking the workers when there's no work to do. We'll also want the worker threads running in the background so they aren't taking priority over foreground work like serving HTTP requests.

To kill a worker, we'll just queue a job to kill the active process, which will be whatever worker picks up the job. This is a simple way to ensure we don't kill a worker that is doing something important. This requires actually using the queue, so a quick couple methods to actually queue a job and some extensions on BlockClosure/BlockContext to make using the queue as simple as forking.

We need to ensure the thread pool is always up and running, and that something is managing it, so we'll hook the system startUp routine and kick off the minimum number of workers and start a single manager process to continually adjust the pool size to match the workload.

And that's it, a simple thread pool using a shared queue to do all the dirty work of dealing with concurrency. I now queue excessively without suffering the punishment entailed by forking excessively. Now rather than...

At the end of the payment process (PayPal) you will be redirected to the download area where you are able to get the latest builds of the PDF version of the book. If you bookmark the page you will be able to download fixes and extra chapters as we integrate them into the online version. By buying the PDF version you support our hard work on the book.

We wish to thank the European Smalltalk User Group, inceptive.be, Cincom Smalltalk and GemStone Smalltalk for generously sponsoring this book. We are looking for additional sponsors. If you are interested, please contact us. If you are a publisher and interested in publishing this material, please let us know.

So please, support the Seaside community and buy the book, I know I will.

SandstoneDb was written mostly as a rails'ish API for a simple object database for use in small office and prototype applications (plus I needed a db for this blog). Which object database wasn't really important to me at the time, it was the API that I wanted, so I made the actual object store backing it pluggable and initially wrote two different store adaptors for it. The first was a memory store which was little more than a dictionary of dictionaries against which I wrote all the unit tests. The second was a prevayler style file based store that used SmartRefStream serialization and loaded everything from disk on startup; this provided a crash proof Squeak images which wouldn't lose data.

I figured eventually, for fun I might get around to writing adaptors for some of the other object database back-ends that are in use: GOODS and Omnibase. I never really got around to it; however, Nico Schwarz has written a GOODS adaptor for SandstoneDb. This will let you hook up multiple squeak images to a single store and should scale better than the file store that SandstoneDb defaults to.

Go check it out and let him know what you think of it. This is just the kind of project that'll help programmers new to Seaside get going and get accustomed to using an object database rather than a relational one. It looks like his first blog post as well, so swing by and leave a comment to encourage more posts, we need more bloggers spreading the word!