Archives for 2006

Multiple threads opening the same Berkeley DB in Tcl

Thanks to the Tcl thread extension, you can use threads within your Tcl scripts with a thread-enabled build and this extension. There’s also a Tcl binding for Berkeley DB (BDB) available, as well. But, what if you want to combine the two, and access the same Berkeley DB from multiple threads in Tcl? Since Berkeley DB is free-threaded (or thread-safe), this should be simple, right? You’re right, it should be but it was pretty non-obvious, to me at least.

It’s not a bug, it’s just an undocumented feature!

First off, the BDB documentation makes mention of DB_THREAD needing to be set on the environment handle to get the free-threaded behavior, but the berkdb env documentation lacks any mention of how to do this. Turns out, the parameter -thread is undocumented, but does set DB_THREAD as expected. Fantastic! That’s all you should need to know, right? Wrong. There’s a peculiar constraint (bug?) which I ran up against, scratching my head, reading (and re-reading) the BDB source, trying to understand. Here’s an example script I started with:

package require Thread

set t1 [thread::create]
thread::send $t1 {
  package require Db_tcl
  set e [berkdb env -create -home bdb -thread -cdb]
  set db [berkdb open -env $e -thread -create -hash tables.db test]
}
thread::send $t1 {$db put foo bar}
  # => 0
thread::send $t1 {$db get foo}
  # => {foo bar}

set t2 [thread::create]
thread::send $t2 {
  package require Db_tcl
  set e [berkdb env -create -home bdb -thread -cdb]
  set db [berkdb open -env $e -thread -create -hash tables.db test]
}
thread::send $t1 {$db get foo}
  # => error: NULL db info pointer

You’d think this would work, right?

Naturally, what’s happened here is that two threads have attempted to use the same environment, and when the second thread does it, it invalidates the environment for the first thread, resulting in the “NULL db info pointer” error. Fine, I wouldn’t expect this to work for just this reason, so lets try to create the environment once and reuse it in the child threads. We’ll use tsv‘s (thread-shared variables) to share the environment handle across threads.

package require Db_tcl
package require Thread

tsv::set bdb env [berkdb env -create -home bdb -thread -cdb]
  # => env0

set t1 [thread::create]
thread::send $t1 {
  package require Db_tcl
  set e [tsv::get bdb env]
    # => env0
  set db [berkdb open -env $e -thread -create -hash tables.db test]
    # => error: db open: illegal environment
}

Illegal? I’ll show YOU illegal!

This really puzzled me, getting the “db open: illegal environment” error. I looked at the source for db-4.2.52, in file tcl_db_pkg.c around lines 1464–1473:

   1464         switch ((enum bdbenvopen)optindex) {
   1465         case TCL_DB_ENV0:
   1466             arg = Tcl_GetStringFromObj(objv[i], NULL);
   1467             envp = NAME_TO_ENV(arg);
   1468             if (envp == NULL) {
   1469                 Tcl_SetResult(interp,
   1470                     "db open: illegal environment", TCL_STATIC);
   1471                 return (TCL_ERROR);
   1472             }
   1473         }

I mean, look at that. NAME_TO_ENV() is a macro that’s defined as (DB_ENV *)_NameToPtr((name)) which simply fishes data out of DBTCL_GLOBAL __dbtcl_global … it shouldn’t be returning a NULL, here. What gives? Since we have to initialize each thread’s state on creation (it doesn’t inherit anything from the thread that created it), we have to package require Db_tcl and load the BDB module in each thread. I bet there’s something goofy going on there. Looking at Db_tcl_Init(), we see:

     72 int
     73 Db_tcl_Init(interp)
     74     Tcl_Interp *interp;     /* Interpreter in which the package is
     75                      * to be made available. */
...
     97     LIST_INIT(&__db_infohead);
     98     return (TCL_OK);
     99 }

Aha! The villain is revealed!

Oh, look, it initializes the global each time the package is loaded! So, the list that points to the environments gets wiped out once our newly created thread loads the Db_tcl package. While this is frustrating, there’s a work-around: create the environment after creating the threads and loading the Db_tcl package inside of them:

package require Db_tcl
package require Thread

## Create our threads, making sure Db_tcl is loaded.
set t1 [thread::create]
thread::send $t1 {
  package require Db_tcl
}
set t2 [thread::create]
thread::send $t2 {
  package require Db_tcl
}

## Now, we can create the environment once:
tsv::set bdb env [berkdb env -create -home bdb -thread -cdb]

## ... and then, use it in our threads:
thread::send $t1 {
  set e [tsv::get bdb env]
  set db [berkdb open -env $e -thread -create -hash tables.db test]
}
thread::send $t2 {
  set e [tsv::get bdb env]
  set db [berkdb open -env $e -thread -create -hash tables.db test]
}

## See:
thread::send $t1 {$db put foo bar}
  # => 0
thread::send $t1 {$db get foo}
  # => {foo bar}
thread::send $t2 {$db get foo}
  # => {foo bar}

All this, for what?

So, this is how the story ends. It is possible to use BDB across multiple threads in a Tcl application, with the restriction that all threads that will load the Db_tcl package must be created and initialized before you create environments and probably any other operation that relies on the __dbtcl_global structure, as it gets initialized on package load and the single global is shared across all threads. Presumably, this might be considered a bug, in that the structure should probably only be initialized once per process rather than every package load.

Can I do something about it now?

Here’s my proposed patch to fix this, although there’s a potential race
condition here:

$ diff -u tcl_db_pkg.c.orig tcl_db_pkg.c
--- tcl_db_pkg.c.orig   2006-07-17 11:22:20.000000000 -0700
+++ tcl_db_pkg.c        2006-07-17 11:23:40.000000000 -0700
@@ -78,6 +78,7 @@
 {
   int code;
   char pkg[12];
+    static int initialized = 0;

   snprintf(pkg, sizeof(pkg), "%d.%d", DB_VERSION_MAJOR, DB_VERSION_MINOR);
   code = Tcl_PkgProvide(interp, "Db_tcl", pkg);
@@ -98,7 +99,10 @@
   (void)Tcl_LinkVar(
       interp, "__debug_test", (char *)&__debug_test,
       TCL_LINK_INT);
-  LIST_INIT(&__db_infohead);
+    if (!initialized) {
+        initialized = 1;
+        LIST_INIT(&__db_infohead);
+    }
   return (TCL_OK);
 }

My recommendation would be to load the Db_tcl package in a single-threaded environment (before any additional threads are created) to ensure that only one thread initializes __db_infohead, then you can freely create threads and load the Db_tcl package in them without each package load re-initializing the __db_infohead.

If this was helpful, feel free to let me know in the comments below. Or, if you have any questions, ask those too!

UPDATE: I received a response from an Oracle engineer (who now owns Sleepycat) about this issue. Here’s it is:

[…] Although the fix you sent in the SR is one of the
ones needed to allow threaded access to BDB’s Tcl API, it is
not the only one. The __db_infohead is the beginning of a
global linked list and manipulation of that linked list is
not protected in the API. All manipulation of it would need
a mutex. That isn’t necessarily hard, but we have not had
customer demand for multi-threading the Tcl API.

I have fixed our Reference Guide Programming Notes on Tcl to
include a statement that says it does not support multi-threading.

So, if you’d like to see full threaded support in Tcl for Berkeley DB, leave a comment below and we’ll see what kind of demand really exists for it. In the meantime, I might try to work on it myself, just in case.

Tags:
,
,
,

del.icio.us/dossy links since July 10, 2006 at 09:00 AM

del.icio.us/dossy (RSS) links since July 10, 2006 at 09:00 AM:

Breaking the brain crack habit

Thanks to Ze Frank’s 07-11-06 episode (transcript), I realize that I am indeed a brain crack addict:

[…] I run out of ideas every day! Each day I live in mortal fear that I’ve used up the last idea that’ll ever come to me. If you don’t wanna run out of ideas the best thing to do is not to execute them. You can tell yourself that you don’t have the time or resources to do ’em right. Then they stay around in your head like brain crack. No matter how bad things get, at least you have those good ideas that you’ll get to later.

Some people get addicted to that brain crack. And the longer they wait, the more they convince themselves of how perfectly that idea should be executed. And they imagine it on a beautiful platter with glitter and rose petals. And everyone’s clapping for them. But the, but the, but the, but the bummer is most ideas kinda suck when you do ’em. And no matter how much you plan you still have to do something for the first time. And you’re almost guaranteed the first time you do something that it’ll blow. But somebody who does something bad three times still has three times the experience of that other person who’s still dreaming of all the applause. When I get an idea, even a bad one, I try to get it out into the world as fast as possible, ’cause I certainly don’t want to be addicted to brain crack.

Time to start breaking that awful brain crack habit of mine.

Tags:
,

Jacob Rosenberg’s brief history of web servers at AOL

Another AOL employee, Jacob Rosenberg, has started blogging. He’s got the unenviable task of making sure our stuff at AOL keeps running as he’s part of the Operations group. Today, he writes a brief history of various web servers that have come out of AOL in the past several years, including AOLserver.

Go on, show him some love and subscribe to Jacob’s blog and leave him some comments. Lets welcome another AOL voice to the blogosphere!

Tags:
,
,
,
,

del.icio.us/dossy links since July 3, 2006 at 09:00 AM

del.icio.us/dossy (RSS) links since July 3, 2006 at 09:00 AM:

Car mix CD, July 2006

This past weekend I spent reviewing what CD’s I have in the car, shuffling some music out and shuffling some new music in. As part of this, I burned another mix CD, dubbed Car Mix, July 2006. To give folks an idea of my broad musical tastes (or lack thereof), here’s the playlist for your amusement:

  1. Runaway Train (4:26), Soul Asylum (Grave Dancers Union)
  2. No Rain (3:37), Blind Melon (Blind Melon)
  3. Tones Of Home (4:26), Blind Melon (Blind Melon)
  4. My Sharona (4:56), The Knack (Reality Bites)
  5. Locked Out (3:19), Crowded House (Reality Bites)
  6. Tempted 1994 (4:07), Squeeze (Reality Bites)
  7. But Anyway (4:09), Blues Traveler (Blues Traveler)
  8. Hello, Little Girl (2:33), Robert Westenberg, Danielle Ferland (Into The Woods)
  9. A Teenager In Love (2:53), Dion & The Belmonts (Live At Madison Square Garden 1972)
  10. Runaround Sue (8:07), Dion & The Belmonts (Live At Madison Square Garden 1972)
  11. Little Diane (4:35), Dion & The Belmonts, (Live At Madison Square Garden 1972)
  12. Burn Up (4:32), Siouxsie & the Banshees (Peepshow)
  13. I See (3:50), Letters To Cleo (Aurora Gory Alice)
  14. Step Back (2:33), Letters To Cleo (Aurora Gory Alice)
  15. Accidentally Like A Martyr (3:41), Warren Zevon (Excitable Boy)
  16. The Origin Of Love (6:03), Hedwig And The Angry Inch
  17. Bitchin’ In The Kitchen (2:31), Cliff De Young & Jessica Harper (Shock Treatment)
  18. Duel Duet (2:06), Cliff Young (Shock Treatment)

These songs were specifically chosen because they evoke fairly specific memories about particular people from my past, or in some cases, specific moods or emotions that I was feeling at a certain point in time. In a way, these songs hold a special place in my heart, like a treasured photograph. I listen to these songs and they unlock whole portions of my long term memory. This is both good and bad, but I’m starting to realize it’s all good now, since it’s in the past and I can’t change it. I can only learn from it and make the present and future better.

If you’ve known me long enough and remember any of these tunes playing in my car when we hung out, or you’ve sung these songs with me, or listen to the lyrics and think they make me think about you … that’s something special we share together. Maybe it’d be fun to get together and do it again sometime.

Tags:
,

Japanese Pastafarians and Pilates, huh?! Non sequiturs abound!

Taking a quick break while working tonight, I decided to surf some USENET and saw this message in alt.religion.pastafarianism:

coj wrote:

I just saw “The complete book of Pilates”

Shivel me timbels…one flom your lockel Jones San?

To my Japanese Pilates bretheren, I say, “ALLLLLLLLL!” (Of course, the Japanese know that ninjas are cooler …)

(If this makes absolutely no sense to you, perhaps you should brush up on your Engrish.)

Tags:
,
,
,
,
,

jQuery 1.0a (alpha) released June 30, 2006

John Resig announces jQuery 1.0a (alpha). If you do any client-side Javascript, you owe it to yourself to check out jQuery. If you’re a developer of a JS library, you really ought to pay attention to what John’s doing in jQuery, because he’s doing things right.

del.icio.us/dossy links since June 26, 2006 at 09:00 AM

del.icio.us/dossy (RSS) links since June 26, 2006 at 09:00 AM:

AOL Open Services Developer Conference Summer 2006, June 28-29

So, I’m down in Northern Virginia this week for the AOL Open Services Developer Conference Summer 2006, open to AOL Technologies employees, to see and hear about all kinds of stuff that is happening and to talk about where we’re headed in the next few months. The day started out with Sree Kotay starting it off followed by Jon Miller reaffirming that we’re seriously in a transformational phase of AOL’s existance.

The conference is themed around the Lord of the Rings trilogy (natch, as it’s a Time Warner asset). Here, you can see my swank conference badge:

AOL Open Services Developer Conference Summer 2006

I’ve posted a few other photos, which I’ve tagged AOL Open Services Developer Conference Summer 2006.

Overall, the first day of the conference was successful from my experience. I attended some great sessions and saw some promising demos, which I don’t think I can openly discuss here in this space, unfortunately. (Maybe I can, I’ll have to ask.) But, what I can tell you is this: if management is serious about what has been said at this conference, I think AOL is going to genuinely surprise everyone who’s counted them out and keeps asking “so why doesn’t AOL have <X>?”

As I said to Sree tonight, “AOL has to start playing to win, not just play to be in the game.” Funny enough, I think if we did play to win, we actually stand a chance of doing it. I’d really like to see it happen.

UPDATE: Armughan Javaid blogs about the conference and has a Flickr set, too.

UPDATE: Sree blogs about it, too.

Tags:
,
,