activemq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chir...@apache.org
Subject svn commit: r883211 - in /activemq/sandbox/activemq-apollo: activemq-syscall/src/main/java/org/apache/activemq/syscall/ activemq-syscall/src/main/java/org/apache/activemq/syscall/util/ activemq-syscall/src/test/java/org/apache/activemq/syscall/ activem...
Date Mon, 23 Nov 2009 02:08:51 GMT
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() : "";
+    }
+
+}



Mime
View raw message