Apparently Python 2.7 doesn’t come with setuptools installed, and thus, easy_install doesn’t work. I really miss my OSX, but this new job requires Windows because we have SDKs that we work with that are Windows only. So be sure to download and run ez_setup.py after you install Python 2.7, and then be sure to add C:\Python27\Scripts to your users path so that you can just type easy_install like you all ways could on OSX or Linux.

 

I need to get the PID of a running Java process, in this case Glassfish 3 to see if it is running before I run some asadmin commands.

ps -ax | grep "java -cp /opt/bmam/glassfish" | grep -v "grep" | cut -d " " -f 1
26306
 

Looks like Maven 2 is pretty much inline with the generic Ant based build system I have been using for the past 8 years. So I am going to take the plunge and start using Maven 2 so I don’t have to keep maintaining my system. Less time maintaining a build system means more time writing code that actually does something unique.

 

I am working on a Desktop Application project that will need scripting support, specifically scripting support for people familiar with web development. Even though I have prior experience successfully embedding both Lua and Python in server side applications, I have picked Javascript for this project. Mainly for the low barrier to entry for web developers, and the massive amount of documentation for the language. I am specifically testing out SpiderMonkey right now. I struggled trying to get SpiderMonkey to compile in Xcode 3.2.3 and am documenting how I got it to work. The JSAPI User Guide had some incorrect information, so I updated it with the same information here.

First of I assume you know how to include the headers and the libjs.a library in Xcode 3.2.3. The problem came when I tried to compile the simplest of applications. The fix was you have to include a #define at before the #include “jsapi.h”.
Like so:

#define XP_UNIX
#include "jsapi.h"

Also the line:

global = JS_NewGlobalObject(cx, &global_class, NULL, NULL);

was incorrect as well, it should have been:

global = JS_NewObject(cx, &global_class, NULL, NULL);

Here is the corrected code that will compile and run on Xcode 3.2.3

#define XP_UNIX
#include "jsapi.h"

/* The class of the global object. */
static JSClass global_class = {
    "global", JSCLASS_GLOBAL_FLAGS,
    JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
    JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
    JSCLASS_NO_OPTIONAL_MEMBERS
};

/* The error reporter callback. */
void reportError(JSContext *cx, const char *message, JSErrorReport *report)
{
    fprintf(stderr, "%s:%u:%s\n",
            report->filename ? report->filename : "<no filename>",
            (unsigned int) report->lineno,
            message);
}

int main(int argc, const char *argv[])
{
    /* JS variables. */
    JSRuntime *rt;
    JSContext *cx;
    JSObject  *global;
    
    /* Create a JS runtime. */
    rt = JS_NewRuntime(8L * 1024L * 1024L);
    if (rt == NULL)
        return 1;
    
    /* Create a context. */
    cx = JS_NewContext(rt, 8192);
    if (cx == NULL)
        return 1;
    JS_SetOptions(cx, JSOPTION_VAROBJFIX);
    //JS_SetVersion(cx, JSVERSION_LATEST);
    JS_SetErrorReporter(cx, reportError);
    
    /* Create the global object. */
    global = JS_NewObject(cx, &global_class, NULL, NULL);
    if (global == NULL)
        return 1;
    
    /* Populate the global object with the standard globals,
     like Object and Array. */

    if (!JS_InitStandardClasses(cx, global))
        return 1;
    
    //TODO app goes here
    
    /* Cleanup. */
    JS_DestroyContext(cx);
    JS_DestroyRuntime(rt);
    JS_ShutDown();
    return 0;
}

 

I was getting Out of Memory Error: can't create native thread errors on a server, and it was definately not running out of memory, so I hacked this little program together to tell me how many threads I should be able to create.

64K is the minimum stack size that Java will allow on an Intel platform. OSX 10.6.3 Snow Leopard has a hard coded limit of 2560 threads. Leopard Server doesn’t seem to have this limit.
TestThreadStackSize.java

public class TestThreadStackSizes
{
    public static void main(final String[] args)
    {
        Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(final Thread t, final Throwable e)
            {
                System.err.println(e.getMessage());
                System.exit(1);
            }
        });
        int numThreads = 1000;
        if (args.length == 1)
        {
            numThreads = Integer.parseInt(args[0]);
        }

        for (int i = 0; i < numThreads; i++)
        {
            try
            {
                Thread t = new Thread(new SleeperThread());
                t.start();
            }
            catch (final OutOfMemoryError e)
            {
                throw new RuntimeException(String.format("Out of Memory Error on Thread %d", i), e);
            }
        }
    }

    private static class SleeperThread implements Runnable
    {
        public void run()
        {
            try
            {
                Thread.sleep(1000 * 60 * 60);
            }
            catch (final InterruptedException e)
            {
                throw new RuntimeException(e);
            }
        }
    }
}

 

Here is a little code snippet on how to get a list of all the Views from all the Design Documents from all the Databases in a CouchDB instance with couchdbkit.

#!/usr/bin/env python

from couchdbkit import *

server = Server()
dbs = server.all_dbs()
for dbname in dbs:
    db = server.get_or_create_db(dbname)
    result = db.all_docs(startkey=‘_design’, endkey=‘_design0′)
    for doc in result.all():
       designdoc = db.get(doc['id'])
       if ‘views’ in designdoc:
           for view in designdoc['views']:
              print ‘%s/%s/_view/%s’ % (dbname, designdoc['_id'], view)

 

The problem with getting CouchDB to install and run correctly in 64 bit mode of OSX 10.6.x is that the ICU dependency has a broken configure script that just won’t compile in 64 bit mode, even with the correct arguments passed in. The solution is to patch up the configure script and force it to build in 64 bit.
Find the following in the configure script

# Check for potential -arch flags.  It is not universal unless
# there are some -arch flags.  Note that *ppc* also matches
# ppc64.  This check is also rather less than ideal.
case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in  #(
  *-arch*ppc*|*-arch*i386*|*-arch*x86_64*) ac_cv_c_bigendian=universal;;
esac

and change it to look like this

# Check for potential -arch flags.  It is not universal unless
# there are some -arch flags.  Note that *ppc* also matches
# ppc64.  This check is also rather less than ideal.
case "${CC} ${CFLAGS} ${CPPFLAGS} ${LDFLAGS}" in  #(
  *-arch*ppc*) ac_cv_c_bigendian=yes;;
esac

now make sure to compile Erlang in 64 bit mode and CouchDB will link to the ICU compiled with 64 bit mode and work.
Here is an already patched ICU 4.4.1 configure script you can just download and use.

 

I had my CouchDB development environment up and running along just fine until I tried to start adding external httpd handlers written Python. I was starting my CouchDB instance with

sudo launchctl load -w /Library/LaunchDaemons/org.apache.couchdb.plist

and stopping it with

sudo launchctl unload -w /Library/LaunchDaemons/org.apache.couchdb.plist

I would get a cryptic Erlang message with ‘OS Process timeout’. So I figured it was a permissions problem and I was right. I tried chmod on the handler scripts, the directory the handler scripts were in and all kinds of other shots in the dark, until it dawned on me that it was only a problem when the server was started with

sudo launchctl load -w /Library/LaunchDaemons/org.apache.couchdb.plist

so after way to much time was spent trying useless things I dug into the .plist file and found

<key>UserName</key>
<string>couchdb</string>

the problem is that user couchdb doesn’t have permission to do anything and the scripts were owned by root:wheel. I figured I was starting the server through launchctl as sudo it should have root permissions. That isn’t the case. I changed the entry in the .plist to

<key>UserName</key>
<string>root</string>

and all my external handlers started working when couchdb was started using launchctl. I am sure that is a “bad” thing to do, but for my development environment it is ok. What I will do in the actual server environment is make those handlers executable by user couchdb and that should work.

 

Update: this has been applied in CouchDB as of applied in r939443.
Here is the bit you add to jquery.couch.js in the couchdb/www/script directory. I added it right between the query function and the view function. Here is the entire modified jquery.couch.js if you just want to download it and use it without having to edit it yourself.

list: function(list, view, options)
{
    var list = list.split(‘/’);
    var options = options || {};
    var type = ‘GET’;
    var data = null;
    if (options['keys'])
    {
        type = ‘POST’;
        var keys = options['keys'];
        delete options['keys'];
        data = toJSON({‘keys’: keys });
    }
    ajax({
        type: type,
        data: data,
        url: this.uri + ‘_design/’ + list[0] + ‘/_list/’ + list[1] + ‘/’ + view + encodeOptions(options)
    }, options, ‘An error occured accessing the list’);
},

UPDATE: this has also been added in couchapp/couchapp on GitHub.
then inside vendor/couchapp/_attachments/jquery.couch.app.js make the Design object look like this

function Design(db, name)
{
    this.doc_id = "_design/" + name;
    this.view = function(view, opts)
    {
        db.view(name + ‘/’ + view, opts);
    };
    this.list = function(list, view, opts)
    {
        db.list(name + ‘/’ + list, view, opts);
    }
}

and then make the appExports entry in jquery.couch.app.js look like this

var appExports = $.extend({
    db : db,
    design : design,
    view : design.view,
    list : design.list,
    docForm : docForm,
    req : mockReq
}, $.couch.app.app);
 

In a previous post I documented my first pass at implementing ad-hoc queries in CouchDB. I have now abandoned the Reduce step of that process, it doesn’t reduce fast enough in some cases of extremely large data. And I moved all the merging of duplicate document ids to a List function, and I made it much more generic. The List function should work with any Map function that returns keys in the format ["field","value"].

Here is what an Ad-Hoc Map function looks like.

function(doc)
{
  emit(['guid', doc.guid], null);
  emit(['src', doc.sourceServer], null);
  emit(['dest', doc.destServer], null);
}

Here is the generic List function that dedupes the lists based on field selection and returns back JSON compatible with what a normal View function returns.

function(head, req)
{
  var maxResults = parseInt(req.query.maxResults);
  function merge(a, b)
  {
    function sortById(a, b)
    {
      if (a.id > b.id) { return 1; }
      if (b.id > a.id) { return -1; }
      return 0;
    }
    if (a.length > 0 && b.length == 0) { return a; }
    if (b.length > 0 && a.length == 0) { return b; }
    a.sort(sortById);
    b.sort(sortById);
    var result = [];
    while( a.length > 0 && b.length > 0 )
    {
      if (a[0].id < b[0].id) { a.shift(); }
      else if (a[0].id > b[0].id) { b.shift(); }
      else { result.push(a.shift()); b.shift(); }
    }
    return result;
  }
  
  var totalRows = 0;
  var fields = {};
  var field;
  var row;
  while (row = getRow())
  {
    totalRows += 1;
    field = row.key[0];
    if (!fields[field])
    {
      fields[field] = [];
    }
    fields[field].push({ id:row.id, doc:row.doc});
  }
  
  var r = [];
  for (var i in fields)
  {
    r = merge(r,fields[i]);
  }
  if (maxResults > 0) { r = r.slice(0,maxResults); }
  result = {total_rows:totalRows, offset:0, rows:r};
  send(toJSON(result));  
}

A query using curl might look something like this

curl -X POST http://localhost:5984/yourdatabase/_design/yourdesigndoc/_list/merge_search/search_criteria?include_docs=true  -d ‘{"keys":[['guid','0123456789'],['src','home'],['dest','work']]}’

of course the “keys” could include multiple “src” and or “guid” and or “dest” fields in this example as well.

© 2012 Jarrod Roberson: Programming Missives Suffusion theme by Sayontan Sinha