Author: chirino
Date: Mon Nov 23 02:08:51 2009
New Revision: 883211

URL: http://svn.apache.org/viewvc?rev=883211&view=rev
Log:
Beefed up io benchmarker

Added:
    
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/IOBenchmark.java
    
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/RateSampler.java
    
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/Combinator.java
    
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
Modified:
    
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/FileDescriptor.java
    
activemq/sandbox/activemq-apollo/activemq-syscall/src/test/java/org/apache/activemq/syscall/FileDescriptorTest.java

Modified: 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/FileDescriptor.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/FileDescriptor.java?rev=883211&r1=883210&r2=883211&view=diff
==============================================================================
--- 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/FileDescriptor.java
 (original)
+++ 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/FileDescriptor.java
 Mon Nov 23 02:08:51 2009
@@ -115,7 +115,7 @@
     }
 
     public long read(NativeAllocation buffer) throws IOException {
-        long rc = IO.write(fd, buffer.pointer(), buffer.length());
+        long rc = IO.read(fd, buffer.pointer(), buffer.length());
         if (rc == -1) {
             throw error();
         }
@@ -131,7 +131,7 @@
     }
 
     public long read(long offset, NativeAllocation buffer) throws IOException {
-        long rc = IO.pwrite(fd, buffer.pointer(), buffer.length(), offset);
+        long rc = IO.pread(fd, buffer.pointer(), buffer.length(), offset);
         if (rc == -1) {
             throw error();
         }

Added: 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/IOBenchmark.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/IOBenchmark.java?rev=883211&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/IOBenchmark.java
 (added)
+++ 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/IOBenchmark.java
 Mon Nov 23 02:08:51 2009
@@ -0,0 +1,927 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.syscall.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.PrintWriter;
+import java.io.RandomAccessFile;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Random;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.activemq.syscall.Callback;
+import org.apache.activemq.syscall.FileDescriptor;
+import org.apache.activemq.syscall.FutureCallback;
+import org.apache.activemq.syscall.NativeAllocation;
+import org.apache.activemq.util.Combinator;
+import org.apache.activemq.util.IOExceptionSupport;
+import org.apache.activemq.util.IntrospectionSupport;
+import org.apache.activemq.util.MemoryPropertyEditor;
+import org.apache.activemq.util.cli.CommonsCLISupport;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.PosixParser;
+
+import static java.lang.String.*;
+import static org.apache.activemq.syscall.jni.CLibrary.*;
+import static org.apache.activemq.syscall.jni.IO.*;
+import static org.apache.activemq.util.cli.OptionBuilder.*;
+
+/**
+ * This class is used to get a benchmark the raw disk performance.
+ */
+public class IOBenchmark {
+
+    private static final HashSet<String> OPS = new HashSet<String>();
+    private static String op(String v) {
+        OPS.add(v);
+        return v;
+    }
+    private static final String WRITE_OP = op("write");
+    private static final String READ_OP = op("read");
+    
+    private static final HashSet<String> APIS = new HashSet<String>();
+    private static String api(String v) {
+        APIS.add(v);
+        return v;
+    }
+    private static final String JAVA_API = api("java");
+    private static final String NATIVE_BIO_API = api("native-bio");
+    private static final String NATIVE_AIO_DIRECT_API = 
api("native-aio-direct");
+    
+    boolean verbose;
+
+    String blockSize="4k";
+    int blockSizeInBytes=1024*4;
+
+    String fileSize="500M";
+    long blocks=128000;
+    
+    String file = "benchmark.bin";
+    String report = "benchmark.html";
+    int sampleCount = 5;
+    double samplePeriod = 2;
+    
+    String[] api = { JAVA_API, NATIVE_BIO_API, NATIVE_AIO_DIRECT_API };
+    String[] operation = { READ_OP, WRITE_OP };
+    
+    // read|write options
+    boolean[] randomSeek={ false };
+    
+    // read options
+    boolean[] keepDirect={ true };
+    
+    // write options
+    boolean[] sync={ false };
+    boolean[] preallocate={ true };
+    
+    private Options createOptions() {
+        Options options = new Options();
+
+        options.addOption("h", "help",    false, "Display help information");
+        options.addOption("v", "verbose", false, "Verbose");
+
+        options.addOption(ob().id("d").name("file").arg("path")
+                .description("Path to the data file. Default: "+file).op());
+        options.addOption(ob().id("r").name("report").arg("path")
+                .description("Path to the report html that will be generated. 
Default: "+report).op());
+        options.addOption(ob().id("fs").name("file-size").arg("count")
+                .description("Size of the data file.  The larger you make it 
the more likely that the OS will not be able to cache the data. Default: 
"+fileSize).op());
+        options.addOption(ob().id("bs").name("block-size").arg("bytes")
+                .description("The size of each benchmarked io operation. 
Default: "+blockSize).op());
+        options.addOption(ob().id("sc").name("sample-count").arg("number")
+                .description("How many samples should the bench mark take of 
each run. Default: "+sampleCount).op());
+        options.addOption(ob().id("sp").name("sample-period").arg("seconds")
+                .description(format("How many seconds should elapse between 
samples. Default: %.2f", samplePeriod)).op());
+        
+        
options.addOption(ob().id("a").name("api").arg("type,type").args(2).sperator(',')
+                .description("Which api style should get benchmarked.  Pick 
from: "+APIS+".  Default: "+join(api, ",")).op());
+        
options.addOption(ob().id("o").name("operation").arg("value,value").args(2).sperator(',')
+                .description("The type of io operation that should be 
benchmarked.  Default: "+join(operation, ",")).op());
+        
+        // read|write options
+        
options.addOption(ob().id("rs").name("random-seek").arg("true,false").args(2).sperator(',')
+                .description("Should a random seek be done before the io 
operation? Affects: read, write. Default: "+join(randomSeek, ",")).op());
+        
options.addOption(ob().id("kd").name("keep-direct").arg("true,false").args(2).sperator(',')
+                .description("Can direct/native operations skip converting 
native buffers to java byte arrays?  Affects: read, write. Default: 
"+join(keepDirect, ",")).op());
+
+        // write options
+        
options.addOption(ob().id("pr").name("preallocate").arg("true,false").args(2).sperator(',')
+                .description("Should the data file be preallocated before 
running the benchmark? Affects: write. Default: "+join(preallocate, ",")).op());
+        
options.addOption(ob().id("sy").name("sync").arg("true,false").args(2).sperator(',')
+                .description("Should a file sync be performed after each io 
operation? Affects: write. Default: "+join(preallocate, ",")).op());
+
+        return options;
+    }
+
+
+    static private String join(boolean[] values, String seperator) {
+        boolean first=true;
+        StringBuffer sb = new StringBuffer();
+        for (Object v : values) {
+            if( !first ) {
+                sb.append(seperator);
+            }
+            first=false;
+            sb.append(v);
+        }
+        return sb.toString();
+    }
+    
+    static private String join(Object[] values, String seperator) {
+        StringBuffer sb = new StringBuffer();
+        boolean first=true;
+        for (Object v : values) {
+            if( !first ) {
+                sb.append(seperator);
+            }
+            first=false;
+            sb.append(v);
+        }
+        return sb.toString();
+    }
+
+
+    public static void main(String[] args) {
+        String jv = System.getProperty("java.version").substring(0, 3);
+        if (jv.compareTo("1.5") < 0) {
+            System.err.println("This application requires jdk 1.5 or higher to 
run, the current java version is " + System.getProperty("java.version"));
+            System.exit(-1);
+            return;
+        }
+
+        IOBenchmark app = new IOBenchmark();
+        System.exit(app.execute(args));
+    }
+    
+    ///////////////////////////////////////////////////////////////////
+    // Entry point for an embedded users who want to call us with
+    // via command line arguments.
+    ///////////////////////////////////////////////////////////////////
+    public int execute(String[] args) {
+        CommandLine cli = null;
+        try {
+            cli = new PosixParser().parse(createOptions(), args, true);
+        } catch (ParseException e) {
+            System.err.println( "Unable to parse command line options: " + 
e.getMessage() );
+            displayHelp();
+            return 1;
+        }
+
+        if( cli.hasOption("h") ) {
+            displayHelp();
+            return 0;
+        }
+        
+        IOBenchmark benchmark = new IOBenchmark();
+        args = CommonsCLISupport.setOptions(benchmark, cli);
+        try {
+            benchmark.benchmark();
+            return 0;
+        } catch (UsageException e) {
+            System.out.println("Invalid Usage: "+e.getMessage());
+            displayHelp();
+            return -1;
+        } catch (Throwable e) {
+            System.out.flush();
+            if (benchmark.verbose) {
+                System.err.println("ERROR:");
+                e.printStackTrace();
+            } else {
+                System.err.println("ERROR: " + e);
+            }
+            System.err.flush();
+            return -2;
+        }
+    }
+    
+    @SuppressWarnings("serial")
+    static class UsageException extends Exception {
+        public UsageException(String msg) {
+            super(msg);
+        }
+    }
+    
+    public void benchmark() throws IOException, UsageException {
+        for (String v : api) {
+            if( !APIS.contains(v) ) {
+                throw new UsageException("invalid api: "+v);
+            }
+        }
+        for (String v : operation) {
+            if( !OPS.contains(v) ) {
+                throw new UsageException("invalid operation: "+v);
+            }
+        }
+        
+        long lv;
+        try {
+            MemoryPropertyEditor mpe = new MemoryPropertyEditor();
+            mpe.setAsText(blockSize);
+            lv = (Long) mpe.getValue();
+        } catch (Throwable e) {
+            throw new UsageException("invalid block-size: "+blockSize);
+        }
+        blockSizeInBytes = (int) lv;
+        
+        try {
+            MemoryPropertyEditor mpe = new MemoryPropertyEditor();
+            mpe.setAsText(fileSize);
+            lv = (Long) mpe.getValue();
+        } catch (Throwable e) {
+            throw new UsageException("invalid file-size: "+fileSize);
+        }
+        
+        blocks = lv/blockSizeInBytes;
+        if( (lv%blockSizeInBytes)>0 ) {
+            blocks++;
+        }
+        
+        
+        PrintWriter pw = null;
+        if( report!=null ) {
+            pw = new PrintWriter(new FileOutputStream(report));
+        }
+        writeReportHeader(pw);
+        int chartCounter=0;
+        
+        for (String operation : this.operation) {
+            Combinator combinator = new Combinator();
+            if( WRITE_OP.equals(operation) ) {
+                combinator
+                .put("preallocate", array(preallocate))
+                .put("randomSeek", array(randomSeek))
+                .put("sync", array(sync));
+            } else if( READ_OP.equals(operation) ) {
+                combinator.put("randomSeek", array(randomSeek));
+                combinator.put("keepDirect", array(keepDirect));
+            } else {
+                throw new RuntimeException();
+            }
+            for (Map<String, Object> options : combinator.combinations()) {
+                String title = "operation: "+operation+", "+options;
+                System.out.println(title);
+                System.out.println(repeat('-', title.length()));
+
+                ArrayList<Benchmark> results = new 
ArrayList<Benchmark>(this.api.length); 
+                for (String apiName : this.api) {
+                    Benchmark benchmark = createBenchmark(apiName);
+                    benchmark.file = new File(file);
+                    benchmark.operation = operation;
+                    benchmark.apiName = apiName;
+                    benchmark.options = options;
+                    IntrospectionSupport.setProperties(benchmark, options);
+                    benchmark.execute();
+                    results.add(benchmark);
+                }
+                writeReportChart(pw, chartCounter++, results);
+            }
+        }        
+        
+        writeReportFooter(pw);
+        if( pw!=null) {
+            pw.close();
+            System.out.println("Benchmark report stored at: "+report);
+        }
+
+    }
+
+    static private Object[] array(boolean[] value) {
+        Object[] rc = new Object[value.length];
+        for (int i = 0; i < rc.length; i++) {
+            rc[i] = value[i];
+        }
+        return rc ;
+    }
+
+
+    private String repeat(char val, int length) {
+        char [] rc = new char[length];
+        Arrays.fill(rc, val);
+        return new String(rc);
+    }
+
+
+    private void writeReportHeader(PrintWriter pw) {
+        if(pw==null) 
+            return;
+        pw.println("<html>");
+        pw.println("  <head>");
+        pw.println("    <script type='text/javascript' 
src='http://www.google.com/jsapi'></script>");
+        pw.println("    <script type='text/javascript'>");
+        pw.println("      google.load('visualization', '1', 
{'packages':['linechart']});");
+        pw.println("    </script>");
+        pw.println("    <style type='text/css'>");
+        pw.println("      body {font-family:Verdana; font-size:12px; 
color:#666666;}");
+        pw.println("      * {margin:0; padding:0;}");
+        pw.println("      .title {text-align:center;}");
+        pw.println("      .chart-section {width:640px; padding: 10px; margin: 
0px auto; clear: both;}");
+        pw.println("      .chart-props {width:120px; padding:0; 
padding-top:5px; float:left; text-align:right; }");
+        pw.println("      .chart-graph {width: 500px; height: 200px; 
float:right; }");
+        pw.println("    </style>");
+        pw.println("  </head>");
+        pw.println("  <body>");
+        pw.println("  <div class='title'> ");
+        pw.println(format("    File Size: "+fileSize+", Block Size: 
"+blockSize+", Sample Period: %.2f, Samples: "+sampleCount, samplePeriod));
+        pw.println("  </div>");
+    }
+    
+    private void writeReportChart(PrintWriter pw, int id, ArrayList<Benchmark> 
data) {
+        if(pw==null) 
+            return;
+        Benchmark d1 = data.get(0);
+        
+        String titleX = String.format("seconds", samplePeriod);
+        String titleY = "operations / second";
+        
+        pw.println("    <div class='chart-section'>");
+        pw.println("      <div class='chart-props'>");
+        pw.print(  "        <div>operation: "+d1.operation+"</div>");
+        for (Entry<String, Object> entry : new TreeMap<String, 
Object>(d1.options).entrySet()) {
+          pw.print("<div>"+entry.getKey()+": "+entry.getValue()+"</div>");
+        }
+        pw.println();
+        pw.println("      </div>");
+        pw.println("      <div id='chart_"+id+"' class='chart-graph '></div>");
+        pw.println("    </div>");
+        pw.println("    <script type='text/javascript'>");
+        pw.println("      google.setOnLoadCallback(draw_chart_"+id+");");
+        pw.println("      function draw_chart_"+id+"() {");
+        pw.println("        var data = new google.visualization.DataTable();");
+        pw.println("        data.addColumn('string', 'Period');");
+        
+        for (Benchmark d : data) {
+            pw.println("        data.addColumn('number', '"+d.apiName+"');");
+        }
+        pw.println("        data.addRows([");
+        for( int i=0; i < sampleCount; i++ ) {
+            if( i!=0 ) {
+                pw.println(",");
+            }
+            pw.print(String.format("          ['%.2f'", samplePeriod*(i+1)));
+            for (Benchmark d : data) {
+                double value = 0;
+                if( d.samples.size() >i ) {
+                    value = d.samples.get(i);
+                }
+                pw.print(String.format(", %.2f",value));
+            }
+            pw.print("]");
+        }
+        
+        pw.println("        ]);");
+        pw.println("        var chart = new 
google.visualization.LineChart(document.getElementById('chart_"+id+"'));");
+        pw.println("        chart.draw(data, {legend: 'bottom', 
smoothLine:true, titleX:'"+titleX+"', titleY:'"+titleY+"' });");
+        pw.println("      }");
+        pw.println("    </script>");
+        
+    }
+
+    private void writeReportFooter(PrintWriter pw) {
+        if(pw==null) 
+            return;
+        pw.println("  </body>");
+        pw.println("</html>");
+    }
+
+    private Benchmark createBenchmark(String api) {
+        if( JAVA_API.equals(api) ) 
+            return new JavaApi();
+        if( NATIVE_BIO_API.equals(api) ) 
+            return new NativeBioApi();
+        if( NATIVE_AIO_DIRECT_API.equals(api) ) {
+            return new NativeDirectAioApi();
+        }
+        throw new RuntimeException("Unsupported API: "+api);
+    }
+
+    abstract class Benchmark {
+        
+        public Map<String, Object> options;
+        public File file;
+        public String apiName;
+        public String operation;
+        public boolean randomSeek; 
+        public boolean sync;
+        public boolean preallocate;
+        public boolean keepDirect;
+        public ArrayList<Double> samples;
+        
+        final public void execute() throws IOException {
+            
+            boolean write;
+            if( WRITE_OP.equals(operation) ) {
+                write = true;
+            } else if( READ_OP.equals(operation) ) {
+                write = false;
+            } else {
+                throw new RuntimeException();
+            }
+            
+            System.out.println("  api: "+apiName);
+            
+            AtomicLong ioCount=new AtomicLong();
+            RateSampler sampler = new RateSampler(ioCount, sampleCount, 
samplePeriod);
+            sampler.verbose = verbose;
+            try {
+                
+                Callback<byte[]> callback=null;
+                if( write ) {
+                    if( preallocate ) {
+                        preallocate();
+                    } else {
+                        file.delete();
+                    }
+                } else {
+                    if( !file.exists() ) {
+                        preallocate();
+                    } else {
+                        if( file.length() != blocks*blockSizeInBytes ) {
+                            file.delete();
+                            preallocate();
+                        }
+                    }
+                    if(keepDirect) {
+                        callback = new Callback<byte[]>() {
+                            public void onSuccess(byte[] result) {
+                            }
+                            public void onFailure(Throwable exception) {
+                            }
+                        };
+                    }
+                }
+                
+                Random rand=null;
+                if( randomSeek ) {
+                    rand = new Random((23<<16)/53);
+                }
+                
+
+                init(write);
+                if( verbose ) {
+                    System.out.print("    sampling: ");
+                }
+                sampler.start();
+                outer: while( true ) {
+                    seek(0);
+                    for( long i=0; i < blocks; i++) {
+                        if( write ) {
+                            if( keepDirect ) {
+                                if( rand!=null ) {
+                                    write(rand.nextLong()%blocks);
+                                } else {
+                                    write();
+                                }
+                            } else {
+                                if( rand!=null ) {
+                                    write(rand.nextLong()%blocks, block());
+                                } else {
+                                    write(block());
+                                }
+                            }
+                            if( sync ) {
+                                sync();
+                            }
+                        } else {
+                            if( keepDirect ) {
+                                if( rand!=null ) {
+                                    read(rand.nextLong()%blocks, callback);
+                                } else {
+                                    read(callback);
+                                }
+                            } else {
+                                if( rand!=null ) {
+                                    read(rand.nextLong()%blocks);
+                                } else {
+                                    read();
+                                }
+                            }
+                        }
+                        ioCount.incrementAndGet();
+                        if( !sampler.isAlive() ) {
+                            break outer;
+                        }
+                    }
+                }
+            } finally {
+                if( verbose ) {
+                    System.out.println(" done");
+                }
+                dispose();
+            }
+            samples = sampler.getSamples();
+            System.out.print("    samples (operations/second): ");
+            boolean first=true;
+            for (Double s : samples) {
+                if( !first ) {
+                    System.out.print(", ");
+                }
+                first=false;
+                System.out.print(String.format("%.2f", s));
+            }
+            System.out.println();
+            System.out.println();
+
+        }
+
+        protected void preallocate() throws IOException {
+            // Pre-allocate the data file before we start sampling.
+            if( verbose ) {
+                System.out.println("    creating data file: ... ");
+            }
+            init(true);
+            for( long i=0; i < blocks; i++) {
+                write();
+            }
+            sync();
+            dispose();
+        }
+
+        abstract protected void init(boolean write) throws IOException;
+        abstract protected void dispose() throws IOException;
+        abstract protected void seek(long pos) throws IOException;
+        abstract protected void sync() throws IOException;
+        
+        abstract protected void write() throws IOException;
+        protected void write(long pos) throws IOException {
+            seek(pos);
+            write();
+        }
+        
+        abstract protected void write(byte []data) throws IOException;
+        protected void write(long pos, byte []data) throws IOException {
+            seek(pos);
+            write(data);
+        }
+        
+        abstract protected void read() throws IOException;
+        abstract protected void read(Callback<byte[]> callback) throws 
IOException;
+        protected void read(long pos) throws IOException {
+            seek(pos);
+            read();
+        }
+        protected void read(long pos, Callback<byte[]> callback) throws 
IOException {
+            seek(pos);
+            read(callback);
+        }
+
+    }
+    
+    
+    final class NativeDirectAioApi extends Benchmark {
+        
+        private FileDescriptor fd;
+        private NativeAllocation data;
+        private byte[] block;
+        private long offset;
+        private FutureCallback<Long> callback;
+
+        @Override
+        protected void init(boolean write) throws IOException {
+            block = block();
+            data = NativeAllocation.allocate(block);
+            if( write ) {
+                int oflags =  O_CREAT | O_TRUNC | O_WRONLY;
+                int mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
+                fd = FileDescriptor.open(file, oflags, mode);
+            } else {
+                int oflags =  O_RDONLY;
+                fd = FileDescriptor.open(file, oflags);
+            }
+            fd.enableDirectIO();
+        }
+
+        @Override
+        protected void dispose() throws IOException {
+            if( data!=null ) 
+                data.free();
+            if( fd!=null ) 
+                fd.close();
+        }
+
+        @Override
+        protected void seek(long pos) throws IOException {
+            offset=pos;
+        }
+
+        @Override
+        protected void sync() throws IOException {
+        }
+
+        private FutureCallback<Long> nextCallback(final Callback<byte[]> next) 
throws InterruptedIOException, IOException {
+            if( callback!=null ) {
+                try {
+                    offset += callback.get();
+                } catch (InterruptedException e) {
+                    throw new InterruptedIOException();
+                } catch (ExecutionException e) {
+                    throw IOExceptionSupport.create(e.getCause());
+                }
+                callback=null;
+            }
+            callback = new FutureCallback<Long>() {
+                @Override
+                public void onSuccess(Long result) {
+                    if( next != null ) {
+                        memmove(block, data.pointer(), data.length());
+                        next.onSuccess(block);
+                    }
+                    super.onSuccess(result);
+                }
+            };
+            return callback;
+        }
+        
+        @Override
+        protected void write() throws IOException {
+            write(offset);
+        }
+        
+        @Override
+        protected void write(long offset) throws IOException {
+            fd.write(offset, data, nextCallback(null));
+        }
+
+        @Override
+        protected void read() throws IOException {
+            read(offset);
+        }
+        
+        protected void read(long offset) throws IOException {
+            fd.read(offset, data, nextCallback(null));
+        }
+
+        @Override
+        protected void read(long offset, Callback<byte[]> callback) throws 
IOException {
+            fd.read(offset, data, nextCallback(callback));
+        }
+        
+        @Override
+        protected void read(Callback<byte[]> callback) throws IOException {
+            read(offset, callback);
+        }
+
+        @Override
+        protected void write(byte[] block) throws IOException {
+            write(offset, block);
+        }
+
+        @Override
+        protected void write(long offset, byte[] block) throws IOException {
+            FutureCallback<Long> callback = nextCallback(null);
+            memmove(data.pointer(), block, data.length());
+            fd.write(offset, data, callback);
+        }
+
+    }
+    
+    final class NativeBioApi extends Benchmark {
+        
+        private FileDescriptor fd;
+        private NativeAllocation data;
+        private byte[] block;
+
+        @Override
+        protected void init(boolean write) throws IOException {
+            block = block();
+            data = NativeAllocation.allocate(block);
+            if( write ) {
+                int oflags =  O_CREAT | O_TRUNC | O_WRONLY;
+                int mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
+                fd = FileDescriptor.open(file, oflags, mode);
+            } else {
+                int oflags =  O_RDONLY;
+                fd = FileDescriptor.open(file, oflags);
+            }
+        }
+
+        @Override
+        protected void dispose() throws IOException {
+            if( data!=null ) 
+                data.free();
+            if( fd!=null ) 
+                fd.close();
+        }
+
+        @Override
+        protected void seek(long pos) throws IOException {
+            fd.seek(pos);
+        }
+
+        @Override
+        protected void sync() throws IOException {
+            fd.sync();
+        }
+
+        @Override
+        protected void write() throws IOException {
+            fd.write(data);
+        }
+        
+        @Override
+        protected void read() throws IOException {
+            long count = fd.read(data);
+            if( count < data.length() ) {
+                throw new IOException("Expecting a full read.");
+            }
+        }
+
+        @Override
+        protected void read(Callback<byte[]> callback) throws IOException {
+            fd.read(data);
+            memmove(block, data.pointer(), data.length());
+            callback.onSuccess(block);
+        }
+
+        @Override
+        protected void write(byte[] block) throws IOException {
+            memmove(data.pointer(), block, data.length());
+            fd.write(data);
+        }
+
+    }
+    
+    final class JavaApi extends Benchmark {
+        
+        private RandomAccessFile raf;
+        private byte data[];
+
+        @Override
+        protected void init(boolean write) throws IOException {
+            data = block();
+            if( write ) {
+                raf = new RandomAccessFile(file, "rw");
+            } else {
+                raf = new RandomAccessFile(file, "r");
+            }
+        }
+
+        @Override
+        protected void dispose() throws IOException {
+            if( raf!=null ) 
+                raf.close();
+        }
+
+        @Override
+        protected void seek(long pos) throws IOException {
+            raf.seek(pos);
+        }
+
+        @Override
+        protected void sync() throws IOException {
+            raf.getFD().sync();
+        }
+
+        @Override
+        protected void write() throws IOException {
+            raf.write(data);
+        }
+        
+        @Override
+        protected void read() throws IOException {
+            raf.readFully(data);
+        }
+
+        @Override
+        protected void read(Callback<byte[]> callback) throws IOException {
+            raf.readFully(data);
+            callback.onSuccess(data);
+        }
+
+        @Override
+        protected void write(byte[] data) throws IOException {
+            raf.write(data);
+        }
+
+    }
+    
+    Random DATA_RANDOM = new Random();
+    private byte[] block() {
+        byte []data = new byte[blockSizeInBytes];
+        for (int i = 0; i < data.length; i++) {
+            data[i] = (byte)('a'+(DATA_RANDOM.nextInt(26)));
+        }
+        return data;
+    }
+
+    private void displayHelp() {
+        System.err.flush();
+        String app = System.getProperty("diskbenchmark.application");
+        if( app == null ) {
+            try {
+                URL location = 
getClass().getProtectionDomain().getCodeSource().getLocation();
+                String[] split = location.toString().split("/");
+                if( split[split.length-1].endsWith(".jar") ) {
+                    app = split[split.length-1];
+                }
+            } catch (Throwable e) {
+            }
+            if( app == null ) {
+                app = getClass().getSimpleName();
+            }
+        }
+
+        // The commented out line is 80 chars long.  We have it here as a 
visual reference
+//      p("                                                                    
            ");
+        p();
+        p("Usage: "+ app +" [options]");
+        p();
+        p("Description:");
+        p();
+        pw("  "+app+" is a disk benchmarker.", 2);
+        p();
+
+        p("Options:");
+        p();
+        PrintWriter out = new PrintWriter(System.out);
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printOptions(out, 78, createOptions(), 2, 2);
+        out.flush();
+        p();
+    }
+    
+
+    private void p() {
+        System.out.println();
+    }
+    private void p(String s) {
+        System.out.println(s);
+    }
+    private void pw(String message, int indent) {
+        PrintWriter out = new PrintWriter(System.out);
+        HelpFormatter formatter = new HelpFormatter();
+        formatter.printWrapped(out, 78, indent, message);
+        out.flush();
+    }
+
+
+    public void setVerbose(boolean verbose) {
+        this.verbose = verbose;
+    }
+    public void setBlockSize(String blockSize) {
+        this.blockSize = blockSize;
+    }
+    public void setFileSize(String fileSize) {
+        this.fileSize = fileSize;
+    }
+    public void setBlocks(long blocks) {
+        this.blocks = blocks;
+    }
+    public void setFile(String file) {
+        this.file = file;
+    }
+    public void setReport(String report) {
+        this.report = report;
+    }
+    public void setSampleCount(int sampleCount) {
+        this.sampleCount = sampleCount;
+    }
+    public void setSamplePeriod(double samplePeriod) {
+        this.samplePeriod = samplePeriod;
+    }
+    public void setApi(String[] api) {
+        this.api = api;
+    }
+    public void setOperation(String[] operation) {
+        this.operation = operation;
+    }
+    public void setRandomSeek(boolean[] randomSeek) {
+        this.randomSeek = randomSeek;
+    }
+    public void setKeepDirect(boolean[] keepDirect) {
+        this.keepDirect = keepDirect;
+    }
+    public void setSync(boolean[] sync) {
+        this.sync = sync;
+    }
+    public void setPreallocate(boolean[] preallocate) {
+        this.preallocate = preallocate;
+    }
+
+}

Added: 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/RateSampler.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/RateSampler.java?rev=883211&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/RateSampler.java
 (added)
+++ 
activemq/sandbox/activemq-apollo/activemq-syscall/src/main/java/org/apache/activemq/syscall/util/RateSampler.java
 Mon Nov 23 02:08:51 2009
@@ -0,0 +1,86 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.activemq.syscall.util;
+
+import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static java.util.concurrent.TimeUnit.*;
+
+public class RateSampler extends Thread {
+    private final AtomicReference<ArrayList<Double>> samples = new 
AtomicReference<ArrayList<Double>>();
+    private final AtomicLong metric;
+    private final int count;
+    private final long period;
+    public boolean verbose;
+    
+    public RateSampler(AtomicLong metric, int count, double periodInSecs) {
+        super("Sampler");
+        this.metric = metric;
+        this.count = count;
+        this.period = ns(periodInSecs);
+        setPriority(MAX_PRIORITY);
+        setDaemon(true);
+    }
+    
+    static final long NANOS_PER_SECOND = NANOSECONDS.convert(1, SECONDS);
+
+    static private long ns(double v) {
+        return (long)(v*NANOS_PER_SECOND);
+    }
+
+    
+    @Override
+    public void run() {
+        ArrayList<Double> samples = new ArrayList<Double>(count);
+        try {
+            long sleepMS = period/1000000;
+            int sleepNS = (int) (period%1000000);
+            long currentValue, now;
+            long lastValue = metric.get();
+            long lastTime = System.nanoTime();
+            
+
+            for (int i = 0; i < count; i++) {
+                if( verbose ) {
+                    System.out.print(".");
+                }
+                Thread.sleep(sleepMS,sleepNS);
+                
+                now = System.nanoTime();
+                currentValue = metric.get();
+                
+                double t = (now-lastTime);
+                t = t/NANOS_PER_SECOND;
+                t = (currentValue-lastValue)/t;
+                samples.add(t);
+                
+                lastTime=now;
+                lastValue=currentValue;
+            }
+        } catch (InterruptedException e) {
+        } finally {
+            this.samples.set(samples);
+        }
+    }
+    
+    public synchronized ArrayList<Double> getSamples() {
+        return samples.get();
+    }
+}
\ No newline at end of file

Modified: 
activemq/sandbox/activemq-apollo/activemq-syscall/src/test/java/org/apache/activemq/syscall/FileDescriptorTest.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-apollo/activemq-syscall/src/test/java/org/apache/activemq/syscall/FileDescriptorTest.java?rev=883211&r1=883210&r2=883211&view=diff
==============================================================================
--- 
activemq/sandbox/activemq-apollo/activemq-syscall/src/test/java/org/apache/activemq/syscall/FileDescriptorTest.java
 (original)
+++ 
activemq/sandbox/activemq-apollo/activemq-syscall/src/test/java/org/apache/activemq/syscall/FileDescriptorTest.java
 Mon Nov 23 02:08:51 2009
@@ -78,7 +78,7 @@
 
         NativeAllocation buffer = allocate(expected.length());
 
-        int oflags = O_NONBLOCK | O_RDONLY;
+        int oflags = O_RDONLY;
         FileDescriptor fd = FileDescriptor.open(file, oflags);
         
         try {
@@ -92,5 +92,35 @@
 
         assertEquals(expected, buffer.string() );
         buffer.free();
+    }
+    
+    @Test
+    public void read() throws IOException, InterruptedException, 
ExecutionException, TimeoutException {
+        assumeThat(AIO.SUPPORTED, is(true));
+        
+        String expected = "Hello World";
+        
+        File file = 
dataFile(FileDescriptorTest.class.getName()+".writeWithACallback.data");
+        writeFile(file, expected);
+
+        NativeAllocation buffer = allocate(6);
+
+        int oflags = O_RDONLY;
+        FileDescriptor fd = FileDescriptor.open(file, oflags);
+        try {
+        
+            long size = fd.read(buffer);
+            assertEquals(6, size);
+            assertEquals(expected.substring(0, 6), buffer.string());
+            
+            size = fd.read(buffer);
+            assertEquals(expected.length()-6, size);
+            assertEquals(expected.substring(6), buffer.view(0, size).string());
+        
+        } finally {
+            fd.dispose();
+        }
+        buffer.free();
     }    
+
 }

Added: 
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/Combinator.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/Combinator.java?rev=883211&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/Combinator.java
 (added)
+++ 
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/Combinator.java
 Mon Nov 23 02:08:51 2009
@@ -0,0 +1,326 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.util;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+/**
+ * Combinator objects are used to compute all the possible combinations given 
a set of combination options.
+ * This class is generally use in conjunction with TestNG test cases generate 
the @Factory and @DataProvider 
+ * results.
+ * 
+ * @author <a href="http://hiramchirino.com";>Hiram Chirino</a>
+ */
+public class Combinator {
+
+    private Combinator parent;
+    private ArrayList<Combinator> children = new ArrayList<Combinator>();
+    
+       private LinkedHashMap<String, ComboOption> comboOptions = new 
LinkedHashMap<String, ComboOption>();
+       private int annonymousAttributeCounter;
+       
+       public Combinator() {
+    }
+       
+    public Combinator(Combinator parent) {
+        this.parent = parent;
+    }
+
+    // For folks who like to use static imports to achieve a more fluent usage 
API.
+       public static Combinator combinator() {
+               return new Combinator();
+       }
+               
+       static class ComboOption {
+               final String attribute;
+               final LinkedHashSet<Object> values = new 
LinkedHashSet<Object>();
+
+               public ComboOption(String attribute, Collection<Object> 
options) {
+                       this.attribute = attribute;
+                       this.values.addAll(options);
+               }
+       }
+
+       
+       public ArrayList<Combinator> all() {
+        ArrayList<Combinator> rc = new ArrayList<Combinator>();
+        root()._all(rc);
+        return rc;
+    }
+    
+       private void _all(ArrayList<Combinator> rc) {
+           rc.add(this);
+        for (Combinator c : children) {
+            c._all(rc);
+        }          
+       }
+       
+       public Combinator put(String attribute, Object... options) {
+               ComboOption co = this.comboOptions.get(attribute);
+               if (co == null) {
+                       this.comboOptions.put(attribute, new 
ComboOption(attribute, Arrays.asList(options)));
+               } else {
+                       co.values.addAll(Arrays.asList(options));
+               }
+               return this;
+       }
+       
+    public Combinator and() {
+        Combinator combinator = new Combinator(this);
+        children.add(combinator);
+        return combinator;
+    }
+
+       
+       public Combinator add(Object... options) {
+               put(""+(annonymousAttributeCounter++), options);
+               return this;
+       }
+       
+//     @SuppressWarnings("unchecked")
+//     public void addFromContext(ApplicationContext applicationContext, 
String name) {
+//             List<Object> list = (List)applicationContext.getBean(name);
+//             Object[] options = list.toArray();
+//             add(options);
+//     }
+//     
+//     public void addAllFromContext(ApplicationContext applicationContext, 
String name) {
+//             List<List<Object>> list = 
(List)applicationContext.getBean(name);
+//             for (List<Object> l : list) {
+//                     Object[] options = l.toArray();
+//                     add(options);
+//             }
+//     }
+
+
+       public Set<Map<String, Object>> combinations() {
+           return root()._combinations();
+       }
+
+    private Combinator root() {
+        Combinator c=this;
+        while( c.parent!=null ) {
+            c = c.parent;
+        }
+        return c;
+    }
+
+    private Set<Map<String, Object>> _combinations() {
+        LinkedHashSet<Map<String, Object>> rc = new LinkedHashSet<Map<String, 
Object>>();
+        List<Map<String, Object>> expandedOptions = new ArrayList<Map<String, 
Object>>();
+        expandCombinations(new ArrayList<ComboOption>(comboOptions.values()), 
expandedOptions);
+        rc.addAll(expandedOptions);
+        for (Combinator c : children) {
+            rc.addAll(c._combinations());
+        }
+               return rc;
+    }
+
+       private void expandCombinations(List<ComboOption> optionsLeft, 
List<Map<String, Object>> expandedCombos) {
+               if (!optionsLeft.isEmpty()) {
+                       Map<String, Object> map;
+                       if (comboOptions.size() == optionsLeft.size()) {
+                               map = new LinkedHashMap<String, Object>();
+                               expandedCombos.add(map);
+                       } else {
+                               map = expandedCombos.get(expandedCombos.size() 
- 1);
+                       }
+
+                       LinkedList<ComboOption> l = new 
LinkedList<ComboOption>(optionsLeft);
+                       ComboOption comboOption = l.removeFirst();
+                       int i = 0;
+                       for (Iterator<Object> iter = 
comboOption.values.iterator(); iter.hasNext();) {
+                               Object value = iter.next();
+                               if (i != 0) {
+                                       map = new LinkedHashMap<String, 
Object>(map);
+                                       expandedCombos.add(map);
+                               }
+                               map.put(comboOption.attribute, value);
+                               expandCombinations(l, expandedCombos);
+                               i++;
+                       }
+               }
+       }
+
+       /**
+        * Creates a bean for each combination of the type specified by clazz 
arguement and uses setter/field 
+        * injection to initialize the Bean with the combination values.
+        * 
+        * @param <T>
+        * @param clazz
+        * @return
+        * @throws InstantiationException
+        * @throws IllegalAccessException
+        */
+       public <T> Object[] combinationsAsBeans(Class<T> clazz) throws 
Exception {
+               Set<Map<String, Object>> combinations = combinations();
+               List<T> rc = new ArrayList<T>(combinations.size());
+               for (Map<String, Object> combination : combinations) {
+                       T instance = clazz.newInstance();
+                       
+                       for (Entry<String, Object> entry : 
combination.entrySet()) {
+                               String key = entry.getKey();
+                               Object value = entry.getValue();
+                               try {
+                                       // Try setter injection..
+                                       Method method = 
clazz.getMethod("set"+ucfc(key), value.getClass());
+                                       method.invoke(instance, new 
Object[]{value});
+                               } catch (Exception ignore) {
+                                       // Try property injection..
+                                       Field declaredField = 
clazz.getDeclaredField(key);
+                                       declaredField.set(instance, value);
+                               }
+                       }
+                       if( instance instanceof CombinationAware) {
+                               
((CombinationAware)instance).setCombination(combination);
+                       }
+                       rc.add(instance);
+               }
+               Object[] t = new Object[rc.size()];
+               rc.toArray(t);
+               return t;
+       }
+
+       public <T> Object[][] combinationsAsParameterArgBeans(Class<T> clazz) 
throws Exception {
+               Object[] x = combinationsAsBeans(clazz);
+               Object[][]rc = new Object[x.length][];
+               for (int i = 0; i < rc.length; i++) {
+                       rc[i] = new Object[] {x[i]};
+               }
+               return rc;
+       }
+       
+       public interface BeanFactory<T> {
+               T createBean() throws Exception;
+               Class<T> getBeanClass();
+       }
+       
+       public interface CombinationAware {
+
+               void setCombination(Map<String, Object> combination);
+       }
+
+       
+       /**
+        * Creates a bean for each combination of the type specified by clazz 
argument and uses setter/field 
+        * injection to initialize the Bean with the combination values.
+        * 
+        * @param clazz
+        * @return
+        * @throws InstantiationException
+        * @throws IllegalAccessException
+        */
+       public <T> T[] asBeans(BeanFactory<T> factory) throws Exception {
+               Set<Map<String, Object>> combinations = combinations();
+               List<Object> rc = new ArrayList<Object>(combinations.size());
+               
+               Class<? extends Object> clazz=null;
+               for (Map<String, Object> combination : combinations) {
+                       Object instance = factory.createBean();
+                       if( clazz == null ) {
+                               clazz = instance.getClass();
+                       }
+                       for (Entry<String, Object> entry : 
combination.entrySet()) {
+                               String key = entry.getKey();
+                               Object value = entry.getValue();
+                               try {
+                                       // Try setter injection..
+                                       Method method = 
clazz.getMethod("set"+ucfc(key), value.getClass());
+                                       method.invoke(instance, new 
Object[]{value});
+                               } catch (Exception ignore) {
+                                       // Try property injection..
+                                       setField(clazz, instance, key, value);
+                               }
+                       }
+                       
+                       if( instance instanceof CombinationAware) {
+                               
((CombinationAware)instance).setCombination(combination);
+                       }
+                       rc.add(instance);
+               }
+               
+               T[] t = toArray(factory, rc);
+               rc.toArray(t);
+               return t;
+       }
+
+    @SuppressWarnings("unchecked")
+    private <T> T[] toArray(BeanFactory<T> factory, List<Object> rc) {
+        return (T[]) Array.newInstance(factory.getBeanClass(), rc.size());
+    }
+
+       private void setField(Class<? extends Object> clazz, Object instance, 
String key, Object value) throws NoSuchFieldException, IllegalAccessException {
+               while( clazz!= null ) {
+                       try {
+                               Field declaredField = 
clazz.getDeclaredField(key);
+                               declaredField.setAccessible(true);
+                               declaredField.set(instance, value);
+                               return;
+                       } catch (NoSuchFieldException e) {
+                               // Field declaration may be in a parent 
class... keep looking.
+                               clazz = clazz.getSuperclass();
+                       }
+               }
+       }
+
+       public <T> Object[][] combinationsAsParameterArgBeans(BeanFactory<T> 
factory) throws Exception {
+               Object[] x = asBeans(factory);
+               Object[][]rc = new Object[x.length][];
+               for (int i = 0; i < rc.length; i++) {
+                       rc[i] = new Object[] {x[i]};
+               }
+               return rc;
+       }       
+       
+       /**
+        * Upper case the first character.
+        * @param key
+        * @return
+        */
+       static private String ucfc(String key) {
+               return key.substring(0,1).toUpperCase()+key.substring(1);
+       }
+
+       public Object[][] combinationsAsParameterArgs() {
+               Set<Map<String, Object>> combinations = combinations();
+               Object[][] rc = new Object[combinations.size()][];
+               int i=0;
+               for (Map<String, Object> combination : combinations) {
+                       int j=0;
+                       Object[] arg = new Object[combination.size()];
+                       for (Object object : combination.values()) {
+                               arg[j++] = object;
+                       }
+                       rc[i++] = arg;
+               }
+               return rc;
+       }
+
+}

Added: 
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
URL: 
http://svn.apache.org/viewvc/activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java?rev=883211&view=auto
==============================================================================
--- 
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
 (added)
+++ 
activemq/sandbox/activemq-apollo/activemq-util/src/main/java/org/apache/activemq/util/MemoryPropertyEditor.java
 Mon Nov 23 02:08:51 2009
@@ -0,0 +1,66 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.util;
+
+import java.beans.PropertyEditorSupport;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Converts string values like "20 Mb", "1024kb", and "1g" to long values in
+ * bytes.
+ */
+public class MemoryPropertyEditor extends PropertyEditorSupport {
+    public void setAsText(String text) throws IllegalArgumentException {
+
+        Pattern p = Pattern.compile("^\\s*(\\d+)\\s*(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
+        Matcher m = p.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1))));
+            return;
+        }
+
+        p = Pattern.compile("^\\s*(\\d+)\\s*k(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
+        m = p.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024));
+            return;
+        }
+
+        p = Pattern.compile("^\\s*(\\d+)\\s*m(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
+        m = p.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024));
+            return;
+        }
+
+        p = Pattern.compile("^\\s*(\\d+)\\s*g(b)?\\s*$", 
Pattern.CASE_INSENSITIVE);
+        m = p.matcher(text);
+        if (m.matches()) {
+            setValue(Long.valueOf(Long.parseLong(m.group(1)) * 1024 * 1024 * 
1024));
+            return;
+        }
+
+        throw new IllegalArgumentException("Could convert not to a memory 
size: " + text);
+    }
+
+    public String getAsText() {
+        Long value = (Long)getValue();
+        return value != null ? value.toString() : "";
+    }
+
+}


Reply via email to