October 8, 2009

A practical example of using the +X filetype.

What's New

I talked about the 2009.1 +X file type here and here. The archive trigger examples there were not all practical, so here's one that you can actually use.

By default, the spec depot creates a new file on your OS filesystem per revision, so sites creating many labels, branches, etc, might run into a problem where the filesystem runs out of inodes, resulting in an end-user error like this:

Label LABENAME saved.
Warning: couldn't archive to spec depot (spec/label/.p4s)
mkdir: spec/label/LABELNAME,d: Too many links

Naturally, this is less than useful. So, to take advantage of archive triggers in the 2009.1 server, I whipped up what I think is a decent implementation of an external data store using the excellent SQLite as a backend.

It's a really simple schema. All it contains is the path, revision and data for any given spec. You can inspect what the trigger creates by loading the database via the "sqlite3" command line utility:

sqlite> .schema
CREATE TABLE `spec` ( `file` TEXT, `rev` TEXT, `data` CLOB );

See ".help" for more commands.

Now that the spec data is in a relational database, you can run some basic SQL queries against it. For example, the following will tell you which specs have been modified the most:

select rev,file from spec order by rev desc limit 10;

And this one (followed by a p4 equivalent) will let you know which typemap revisions (probably) contained uncompressed binary mappings:

select file,rev from spec where file = 'spec/typemap.p4s' and data like '%ubinary%';
p4 annotate -a //spec/typemap.p4s | grep ubinary

There shouldn't be any real surprises in the trigger code, but one tidbit that you ought to be aware of if you're implementing something of your own, is that on Windows, standard input isn't opened in text-mode by default, so you'll have to change it to binary, perhaps like in this snippet from the trigger source:

#ifdef _WIN32
	// Important:  On Windows, STDIN defaults to TEXT mode.// Changing it to BINARY to avoid data corruption.if(_setmode(_fileno( stdin ), _O_BINARY )==-1){errlog("ERROR:  _setmode():  %s\n",strerror( errno ));return1;}#endif

You can get the source for this trigger in the public depot, here. There are instructions for compilation and usage inside the code. Hopefully it's pretty straight-forward.

This is not supported by Perforce, but I'm still interested in hearing about any comments or bugs you might have! Note that I'm not necessarily going to have much (any?) time to devote time to this, as actual products take precedence ;).