Saturday, April 28, 2007

Book, The Art of Project Management

Recently I have been reading The Art of Project Management written by Scott Berkun, and therefore no time to blog about scripting.

Am I going to move to project management related work, no. The reason I picked up this book is because I was inspired by this blog, Programmers are brain surgeons. The blog quoted something from the book -“Programmers should be trusted. If your brain surgeon told you the operation you need takes five hours, would you pressure him to do it in three?".

Here I will summarise some the quotes that Scott Berkun used in his book:

  • "If I had six hours to cut down a tree, I'd spend four hours sharpening the axe", Abraham Lincoln, chapter 3, how to figure out what to do
  • "A finger points to the moon. Do not confuse the finger for the moon", Zen parable, chapter 4, writing the good vision
  • "Computer are useless. They can only give you answers.", Pablo Picasso, chapter 5, where ideas come from
  • "The two most important tools an architect has are the eraser in the drawing room and the sledgehammer on the construction site.", Frank Lyoyd Wright
  • "There is no such thing as failure. Only giving up too soon.", Jonas Salk
  • "There's a way to do it better, find it.", Thomas Edison
  • "If you want to succeed, double your failure rate.", Tom Watson, IBM
  • "I like working with good people because if I come up with an idea, they come up with a better idea, then I come up with an even better one, and so on: It's a leapfrog process, and the work becomes much better than it would be if I only did exactly what I want.", Terry Gilliam, film director
  • "There are still enormous amounts of trial and error... You go back and forth from observation to theory. You don't know what to look for withour a theory, and you can't check the theory without looking at the fact... I believe that the movement back and forth occurs thousands, even millions of times in the course of a single investigation.", Joshua Lederberg, winner of Nobel Prize, 1958, chapter 6, what to do with ideas once you have them
  • "All know the way; few actually walk it.", Bodhidharma, chapter 8, how to make good decisions
  • "The cause of almost all relationship difficulties is rooted in conflicting or ambiguous expectations around roles and goals", Stephen Covey, author of The 7 Habits of Highly Effective People, chapter 9, communication and relationships
  • "You can blame people who knock things over in the dark, or you can begin to light candles. You're only at fault if you know about the problem and choose to do nothing", Paul Hawken, chapter 11, what to do when things go wrong
  • "What should worry us is not the number of people that oppose us, but how good their reasons are for doing so", Alain de Botton
  • "Trust is at the core of all meaningful relationships. Without trust there can be no giving, no bonding, no risk-taking", Terry Mizrahi, Director of Ecco (Education Centre for Community Organizations), chapter 12, why leadership is based on trust
  • "Believe nothing, no matter where you read it or who has said it, not even if I have said it, unless it agrees with you own reason and your own common sense", Buddha
  • "It is only as a man puts off all foreign support, and stands alone, that I see him to be strong and to prevail... He who knows that power is inborn, that he is weak because he has looked [only] for good out of him and elsewhere, and so perceiving, throws himself unhesitatingly on his thought, instantly rights himself, stands in the erect positions, commands his limbs, works miracles; just as a man who stands on his feet is stronger than a man who stands on his head", Ralph Waldo Emerson, from "Self Reliance"
  • "The world responds to action, and not much else", Scott Adams, chapter 13, how to make things happen
  • "Chances favors the prepared", Louis Pasteur, chapter 14, middle-game strategy
  • "No battle was ever won according to plan, but no battle was ever won without one", Dwight D. Eisenhower
  • "How you play a note is just as important as what the note is", Henry Kaiser, chapter 15, end-game strategy
  • "Every management act is a political act. By this I mean that every management act in some way redistributes or reinforces power", Richard Farson, Management of the Absurd: Paradoxes in Leadership (Simon and Schuster, 1996), chapter 16, power and politics
  • "If you don't know what you are doing, what will deliver which value to whom, and how it will be implemented, the project self-organizers around some other goal or goals. Typically, political wrangling of some kind erupts. This guarantees pointlessness", James Bullock, from Roundtable on Project Management

Also, this must read reference: Saying No: A Short Course for Managers by Richard Brenner


Wednesday, April 18, 2007

clock scan, the perl way

Recently I was helping someone to find out those directories (in yyyymmdd- naming convention) that is 2 weeks old. It can be easily done in Tcl with clock scan. However, not every operating system comes with Tcl. As far as I know Tclsh8.3 is only available in Solaris 9 onwards, but not in Solaris 8.

If I were to do it in shell script, it will be very tough. In this case, I chose the Perl way for my implementation because Perl is available since Solaris 8.

$ cat
#! /usr/bin/perl

if ( $narg < 2 || $narg > 3 ) {
die "Usage: $0   [ago]\n";


# unit
if ( /^second[s]?$/ ) {
} elsif ( /^minute[s]?$/ ) {
} elsif ( /^hour[s]?$/ ) {
} elsif ( /^day[s]?$/ ) {
} elsif ( /^week[s]?$/ ) {
} elsif ( /^month[s]?$/ ) {
} elsif ( /^year[s]?$/ ) {
} else {
        die "Error $unit unknown";

# ago
if ( /^ago$/ ) {

# count
$,=" ";

printf("%04d-%02d-%02d %02d:%02d:%02d\n",$year+1900,$mth+1,$day,$hr,$min,$sec);

$ ./ 2 weeks ago
2007-04-03 18:04:07

$ ./ -2 weeks
2007-04-03 18:04:12

$ ./ 1 year ago
2006-04-17 18:04:17

$ ./ 2 months
2007-06-16 18:04:22

Labels: , , ,

Saturday, April 14, 2007

mkdir, the limit

A friend of mine hit the limit of having no more than 32765 sub-directories. In Solaris 8, it has been documented: "Too many links cause an attempt was made to create more than the maximum number of hard links (LINK_MAX, by default 32767) to a file. Because each subdirectory is a link to its parent directory, the same error results from trying to create too many subdirectories"

So the question is: Is there anything we can do. I don't think so because this is a built in limit in Solaris. What one can do is to ask ourself why we need that many sub-directories and can we change that flat directory structure to a hierarchical. It is pretty obvious that too many files/directories in folder will have a performance issue when an application interacts with it.

Let do an experiment just to convince ourself that indeed there is a limit:

$ uname -a
SunOS myhost 5.9 Generic_118558-11 sun4u sparc SUNW,Sun-Fire-V240

$ psrinfo -v
Status of processor 0 as of: 04/14/2007 12:16:12
  Processor has been on-line since 10/16/2006 09:10:39.
  The sparcv9 processor operates at 1002 MHz,
        and has a sparcv9 floating point processor.
Status of processor 1 as of: 04/14/2007 12:16:12
  Processor has been on-line since 10/16/2006 09:10:38.
  The sparcv9 processor operates at 1002 MHz,
        and has a sparcv9 floating point processor.

$ mkdir test1

$ cd test1

$ time for i in `perl -e '$,=" ";print 1..32768'`
 mkdir $i
mkdir: Failed to make directory "32766"; Too many links
mkdir: Failed to make directory "32767"; Too many links
mkdir: Failed to make directory "32768"; Too many links

real    2m52.716s
user    0m40.830s
sys     2m7.210s

$ cd ..

$ perl
print $nlink,"\n";

As we can see, the maximum number of sub-directories one can create will be 32765. The total links is 32767 because for every directory we create, it creates two links, one for itself (.) and the other one is the parent directory (..)

Let sidetrack a little bit and take a look from the performance angle. It seems to take almost 3 minutes to create 32765 sub-directories. Can it be faster? Let see what interpreted languages like Tcl and Perl can offer.

The perl way:

$ perl -v

This is perl, v5.6.1 built for sun4-solaris-64int
(with 48 registered patches, see perl -V for more detail)

Copyright 1987-2001, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using `man perl' or `perldoc perl'.  If you have access to the
Internet, point your browser at, the Perl Home Page.

$ mkdir test2

$ cd test2

$ time $ perl
for ($i=$start; $i<=$end; $i++) {
real    0m21.098s
user    0m0.180s
sys     0m7.740s
Wow, we are talking about 8 times speed up. How about my favourite Tcl. The Tcl way:
$ cat a.tcl
#! /usr/sfw/bin/tclsh8.3

for { set i 1 } { $i <= 32768 } { incr i } {
        file mkdir $i

$ mkdir test3

$ cd test3

$ time ../a.tcl
can't create directory "32766": too many links
    while executing
"file mkdir $i"
    ("for" body line 2)
    invoked from within
"for { set i 1 } { $i <= 32768 } { incr i } {
        file mkdir $i
    (file "../a.tcl" line 3)

real    0m20.796s
user    0m0.900s
sys     0m8.040s
Wow, I am impressed that Tcl 8.3 (latest is 8.4) is as good as Perl 5.6.1 (latest is 5.8.8)

BTW, to remove that many sub-directories (under test1, test2, test3) 3x32767, it took

$ time /bin/rm -rf test1 test2 test3

real    0m35.425s
user    0m1.210s
sys     0m19.740s
Why perl and Tcl can perform better than the shell script ? Obviously, there is no fork or exec of processes in Perl and Tcl because they have the "mkdir" function call built-in into their interpreter. So how much overhead we are talking about, let's do another experiement.
$ truss mkdir newdir 2>&1 | wc -l

$ truss mkdir u
execve("/usr/bin/mkdir", 0xFFBFFCF4, 0xFFBFFD00)  argc = 2
resolvepath("/usr/lib/", "/usr/lib/", 1023) = 16
resolvepath("/usr/bin/mkdir", "/usr/bin/mkdir", 1023) = 14
stat("/usr/bin/mkdir", 0xFFBFFAC8)              = 0
open("/var/ld/ld.config", O_RDONLY)             Err#2 ENOENT
stat("/usr/lib/", 0xFFBFF5D0)        = 0
resolvepath("/usr/lib/", "/usr/lib/", 1023) = 20
open("/usr/lib/", O_RDONLY)          = 3
mmap(0x00010000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_ALIGN, 3, 0) = 0xFF3A0000
mmap(0x00010000, 98304, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANON|MAP_ALIGN, -1, 0) = 0xFF380000
mmap(0xFF380000, 22677, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0xFF380000
mmap(0xFF396000, 2343, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 24576) = 0xFF396000
munmap(0xFF386000, 65536)                       = 0
memcntl(0xFF380000, 6304, MC_ADVISE, MADV_WILLNEED, 0, 0) = 0
close(3)                                        = 0
stat("/usr/lib/", 0xFFBFF5D0)          = 0
resolvepath("/usr/lib/", "/usr/lib/", 1023) = 18
open("/usr/lib/", O_RDONLY)            = 3
mmap(0xFF3A0000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0xFF3A0000
mmap(0x00010000, 802816, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANON|MAP_ALIGN, -1, 0) = 0xFF280000
mmap(0xFF280000, 701788, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0xFF280000
mmap(0xFF33C000, 24664, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 704512) = 0xFF33C000
munmap(0xFF32C000, 65536)                       = 0
memcntl(0xFF280000, 117372, MC_ADVISE, MADV_WILLNEED, 0, 0) = 0
close(3)                                        = 0
stat("/usr/lib/", 0xFFBFF5D0)         = 0
resolvepath("/usr/lib/", "/usr/lib/", 1023) = 19
open("/usr/lib/", O_RDONLY)           = 3
mmap(0xFF3A0000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0xFF3A0000
mmap(0x00002000, 8192, PROT_NONE, MAP_PRIVATE|MAP_NORESERVE|MAP_ANON|MAP_ALIGN, -1, 0) = 0xFF3FA000
close(3)                                        = 0
mmap(0x00000000, 8192, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0) = 0xFF370000
stat("/usr/platform/SUNW,Sun-Fire-V240/lib/", 0xFFBFF2E0) = 0
resolvepath("/usr/platform/SUNW,Sun-Fire-V240/lib/", "/usr/platform/sun4u-us3/lib/", 1023) = 41
open("/usr/platform/SUNW,Sun-Fire-V240/lib/", O_RDONLY) = 3
mmap(0xFF3A0000, 8192, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED, 3, 0) = 0xFF3A0000
close(3)                                        = 0
getrlimit(RLIMIT_STACK, 0xFFBFF90C)             = 0
brk(0x000245E8)                                 = 0
brk(0x000265E8)                                 = 0
umask(0)                                        = 077
umask(077)                                      = 0
mkdir("u", 0777)                                = 0

Ok, we now know that for every 'mkdir', it calls 48 system functions. So there will be 32,765 x 48 = 1,572,720 system calls in order to create that many directories. In Tcl/Perl, it only takes 6 system calls to create a single directory and that is 8 times less system calls. This tally with our initial speed up calculation.

9364/1:         read(0, " f i l e   m k d i r   t".., 4096)     = 13
9364/1:         stat("t", 0xFFBFE910)                           Err#2 ENOENT
9364/1:         umask(0)                                        = 077
9364/1:         umask(077)                                      = 0
9364/1:         mkdir("t", 0700)                                = 0
9364/1:         write(1, " %  ", 2)                             = 2

Labels: , , , ,

Monday, April 09, 2007

Java System Properties

After understand that Java does not honour TMPDIR, I really want to know what are the default system properties in Java. Hence, I wrote my 2nd Java program to list out the default values of all the system properties.

$ cat

public class b {
        public static void main(String[] args) {
                String value;
                String keys[]={

                for (String key: keys) {
                        System.out.println(key + "=" + value);


$ java b
java.vendor=Sun Microsystems Inc.
java.vm.specification.vendor=Sun Microsystems Inc. Virtual Machine Specification
java.vm.vendor=Sun Microsystems Inc. HotSpot(TM) Client VM
java.specification.vendor=Sun Microsystems Inc. Platform API Specification

If you were to run java as a server, the default library path changes accordingly. If you look one of the library paths, you will see "java -client" (default) and "java -server" load in different sharable object. Does anyone know exactly the difference between the 2, apart from the way they define the young and old generations.

$ uname -a
SunOS chihung 5.10 Generic_118833-36 sun4u sparc SUNW,UltraSPARC-IIi-cEngine

$ java -server b > b.server

$ java -d64 -server b > b.server.d64

$ java -client b > b.client

$ diff b.server b.client
< HotSpot(TM) Server VM
> HotSpot(TM) Client VM
< java.library.path=/usr/jdk/instances/jdk1.5.0/jre/lib/sparc/server:/usr/jdk/instances/jdk1.5.0/jre/lib/sparc:/usr/jdk/instances/jdk1.5.0/jre/../lib/sparc:/lib:/usr/lib:/usr/sfw/lib:/usr/dt/lib:/usr/X11R6/lib:/usr/lib
> java.library.path=/usr/jdk/instances/jdk1.5.0/jre/lib/sparc/client:/usr/jdk/instances/jdk1.5.0/jre/lib/sparc:/usr/jdk/instances/jdk1.5.0/jre/../lib/sparc:/lib:/usr/lib:/usr/sfw/lib:/usr/dt/lib:/usr/X11R6/lib:/usr/lib

$ diff b.server b.server.d64
< HotSpot(TM) Server VM
> HotSpot(TM) 64-Bit Server VM
< java.library.path=/usr/jdk/instances/jdk1.5.0/jre/lib/sparc/server:/usr/jdk/instances/jdk1.5.0/jre/lib/sparc:/usr/jdk/instances/jdk1.5.0/jre/../lib/sparc:/lib:/usr/lib:/usr/sfw/lib:/usr/dt/lib:/usr/X11R6/lib:/usr/lib
> java.library.path=/usr/jdk/instances/jdk1.5.0/jre/lib/sparcv9/server:/usr/jdk/instances/jdk1.5.0/jre/lib/sparcv9:/usr/jdk/instances/jdk1.5.0/jre/../lib/sparcv9:/lib:/usr/lib:/usr/sfw/lib:/usr/dt/lib:/usr/X11R6/lib:/usr/lib
< os.arch=sparc
> os.arch=sparcv9

$ cd /usr/jdk/instances/jdk1.5.0/jre/lib/sparc

$ ls -l client server
total 36778
drwxr-xr-x   2 root     bin          512 Mar 21 10:20 64
-rw-r--r--   1 root     bin         1423 May  3  2006 Xusage.txt
-r--r--r--   1 root     other    11886592 Mar 21 10:21 classes.jsa
lrwxrwxrwx   1 root     root          13 Mar 21 10:20 -> ../
-rwxr-xr-x   1 root     bin      6879100 May  3  2006
-rwxr-xr-x   1 root     bin        41072 May  3  2006

total 19898
drwxr-xr-x   2 root     bin          512 Mar 21 10:20 64
-rw-r--r--   1 root     bin         1423 May  3  2006 Xusage.txt
lrwxrwxrwx   1 root     root          13 Mar 21 10:20 -> ../
-rwxr-xr-x   1 root     bin      10127532 May  3  2006
-rwxr-xr-x   1 root     bin        41072 May  3  2006

Labels: ,

Thursday, April 05, 2007

Java does not honour TMPDIR

My colleague encountered a wierd behaviour in deploying his SunONE application server in Solaris. He realised that when the / partition is near full, he will have problem in starting the daemon.

I understand that most utilities in UNIX honour the TMPDIR environment variable to be the temporary directory. So, the question is, does Java honours TMPDIR ?

Found this with the help of Google. Too bad, Java DOESN'T honour TMPDIR variable. To proof the point, I wrote my very first Java program (FYI, I do not like programming languages start with letter J :-), almost the first except Hello World.

$ cat

public class a {
        public static void main(String[] args) {
                String tmpdir=System.getProperty("");
                System.out.println("Dir: " + tmpdir + "\n");

$ uname -a
SunOS chihung 5.10 Generic_118833-36 sun4u sparc SUNW,UltraSPARC-IIi-cEngine

$ java -version
java version "1.5.0_07"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_07-b03)
Java HotSpot(TM) Client VM (build 1.5.0_07-b03, mixed mode, sharing)

$ cat

public class a {
        public static void main(String[] args) {
                String tmpdir=System.getProperty("");
                System.out.println("Dir: " + tmpdir);

$ javac

$ TMPDIR=/a/b/c java a
Dir: /var/tmp/

$ java a
Dir: /var/tmp/

$ java"/a/b/c" a
Dir: /a/b/c

Labels: ,

Tuesday, April 03, 2007

ZFS with history

I stumbled upon a blog today and it highlighted that the ZFS file system contains the history of all commands executed with respect to the ZFS pool.

Below is the output of the zpool history for my previous blog

# zpool history zpool
History for 'zpool':
2007-03-27.14:46:10 zpool create zpool raidz2 /zdisk/z01 /zdisk/z02 /zdisk/z03 /zdisk/z04 /zdisk/z05 /zdisk/z06 raidz2 /zdisk/z07 /zdisk/z08 /zdisk/z09 /zdisk/z10 /zdisk/z11 /zdisk/z12 raidz2 /zdisk/z13 /zdisk/z14 /zdisk/z15 /zdisk/z16 /zdisk/z17 /zdisk/z18 spare /zdisk/z19 /zdisk/z20
2007-03-27.14:47:06 zfs create zpool/zfs_iscsi
2007-03-27.14:47:21 zfs create zpool/zone_brandz
2007-03-27.14:48:06 zfs set shareiscsi=on zpool/zfs_iscsi
2007-03-27.14:49:36 zfs set shareiscsi=off zpool/zfs_iscsi
2007-03-27.14:50:07 zfs create -V 20m zpool/zfs_iscsi/v20m
2007-03-27.14:50:31 zfs set shareiscsi=on zpool/zfs_iscsi/v20m
2007-03-27.15:17:20 zfs destroy -f zpool/zfs_iscsi/v20m
2007-03-27.15:18:45 zfs create -V 20m zpool/zfs_iscsi/vol20m
2007-03-27.15:19:03 zfs set shareiscsi=on zpool/zfs_iscsi/vol20m
2007-03-27.16:05:09 zfs set volsize=100m zpool/zfs_iscsi/vol20m
2007-03-27.16:05:23 zfs set reservation=100m zpool/zfs_iscsi/vol20m
2007-03-27.16:25:17 zfs create zpool/zfs_samba
2007-03-27.16:55:31 zfs rename zpool/zfs_iscsi/vol20m zpool/zfs_iscsi/vol100m
2007-03-27.17:51:24 zpool scrub zpool
2007-03-27.17:53:23 zpool replace zpool /zdisk/z18 /zdisk/z18new
2007-03-28.11:31:24 zpool scrub zpool

IMO, it is a very nice feature 'cos it captures the life cycle of the ZFS pool (almost). It would be even better if this information is written to the OS so that it can really cover the whole life cycle, including the 'zpool destroy'.

Labels: ,

Monday, April 02, 2007

Solaris + Tcl + Apache + RRDtool, Part 2

In Part 1, I described how I made use of Solaris (zones), Tcl, Apache and RRDtool to provide a generic web frontend in plotting time-based data. However, the input data has to be in RRDtool data input format, where the time stamp has to be in epoch and data has to be colon separated.

In order to make this web frontend to be more usable, I made a number of enhancement:

  • Allow both timestamp to be either in epoch or ISO 8601 format
  • Graph type to be either LINE or AREA (STACK)
  • User supplied field separator

Below images show the web form and the graph:

In fact, it is pretty easy to get the current epoch time:
perl -e 'print time()'.
Just embedded the above in your monitoring script.

Labels: , , ,


Some of the systems monitoring commands with built-in looping functionality, commands such as vmstat, iostat, .... Very often we would like to repeat the same command to monitor certain activities like file size, disk usage.

This shell function does exactly this:

    while :
    eval $cmd
    sleep $sec

Now you just have to provide the interval and the command you like to loop, just like this:

$ loop 5 df -h /
Filesystem             size   used  avail capacity  Mounted on
/dev/md/dsk/d30        5.9G   4.9G   931M    85%    /
Filesystem             size   used  avail capacity  Mounted on
/dev/md/dsk/d30        5.9G   4.9G   931M    85%    /
Filesystem             size   used  avail capacity  Mounted on
/dev/md/dsk/d30        5.9G   4.9G   931M    85%    /

Labels: ,