ws-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From veit...@apache.org
Subject svn commit: r1679747 - in /webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom: attachments/ blob/
Date Sat, 16 May 2015 16:57:37 GMT
Author: veithen
Date: Sat May 16 16:57:36 2015
New Revision: 1679747

URL: http://svn.apache.org/r1679747
Log:
Rewrite the MemoryBlob implementation:
- It now allocates buffers with increasing sizes. This should make the implementation more
efficient over a wider range of blob sizes.
- Add a readOnce() method that consumes the content of the blob and gradually frees the buffers.

Added:
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobChunk.java
  (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobInputStream.java
  (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobOutputStream.java
  (with props)
Modified:
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java?rev=1679747&r1=1679746&r2=1679747&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
(original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
Sat May 16 16:57:36 2015
@@ -20,6 +20,7 @@
 package org.apache.axiom.attachments;
 
 import org.apache.axiom.attachments.Part;
+import org.apache.axiom.blob.MemoryBlob;
 import org.apache.axiom.blob.OverflowableBlob;
 import org.apache.axiom.blob.WritableBlob;
 import org.apache.axiom.blob.WritableBlobFactory;
@@ -234,11 +235,13 @@ final class PartImpl implements Part {
             return detachableInputStream;
         } else {
             WritableBlob content = getContent();
-            InputStream stream = content.getInputStream();
-            if (!preserve) {
-                stream = new ReadOnceInputStreamWrapper(this, stream);
+            if (preserve) {
+                return content.getInputStream();
+            } else if (content instanceof MemoryBlob) {
+                return ((MemoryBlob)content).readOnce();
+            } else {
+                return new ReadOnceInputStreamWrapper(this, content.getInputStream());
             }
-            return stream;
         }
     }
     

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java?rev=1679747&r1=1679746&r2=1679747&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
(original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
Sat May 16 16:57:36 2015
@@ -35,4 +35,12 @@ public interface MemoryBlob extends Writ
     OutputStream getOutputStream();
     long getSize();
     void release();
+
+    /**
+     * Get an input stream that consumes the content of this blob. The memory held by this
blob will
+     * be gradually released as data is read from the stream.
+     * 
+     * @return the input stream to read the data from
+     */
+    InputStream readOnce();
 }

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobChunk.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobChunk.java?rev=1679747&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobChunk.java
(added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobChunk.java
Sat May 16 16:57:36 2015
@@ -0,0 +1,33 @@
+/*
+ * 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.axiom.blob;
+
+final class MemoryBlobChunk {
+    final byte[] buffer;
+    int size;
+    MemoryBlobChunk nextChunk;
+    
+    MemoryBlobChunk(int capacity) {
+        buffer = new byte[capacity];
+    }
+    
+    MemoryBlobChunk allocateNextChunk() {
+        return nextChunk = new MemoryBlobChunk(buffer.length * 2);
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobChunk.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java?rev=1679747&r1=1679746&r2=1679747&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java
(original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java
Sat May 16 16:57:36 2015
@@ -16,242 +16,94 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.axiom.blob;
 
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
 
-import org.apache.axiom.ext.io.ReadFromSupport;
 import org.apache.axiom.ext.io.StreamCopyException;
 
 final class MemoryBlobImpl implements MemoryBlob {
-    // TODO: this should be configurable
-    final static int BUFFER_SIZE = 4096;
-    
-    class OutputStreamImpl extends OutputStream implements ReadFromSupport {
-        public void write(byte[] b, int off, int len) throws IOException {
-            if (committed) {
-                throw new IllegalStateException();
-            }
-            int total = 0;
-            while (total < len) {
-                int copy = Math.min(len-total, BUFFER_SIZE-index);
-                System.arraycopy(b, off, currBuffer, index, copy);
-                total += copy;
-                index += copy;
-                off += copy;
-                if (index >= BUFFER_SIZE) {
-                    addBuffer();
-                }
-            }
-        }
-
-        public void write(byte[] b) throws IOException {
-            this.write(b, 0, b.length);
-        }
-        
-        byte[] writeByte = new byte[1];
-        public void write(int b) throws IOException {
-            writeByte[0] = (byte) b;
-            this.write(writeByte, 0, 1);
-        }
-
-        public void close() throws IOException {
-            committed = true;
-        }
-
-        public long readFrom(InputStream in, long length) throws StreamCopyException {
-            return MemoryBlobImpl.this.readFrom(in, length, false);
-        }
-    }
-
-    class InputStreamImpl extends InputStream {
-        private int i;
-        private int currIndex;
-        private int totalIndex;
-        private int mark;
-        private byte[] currBuffer;
-        private byte[] read_byte = new byte[1];
-        
-        public InputStreamImpl() {
-        }
-
-        public int read() throws IOException {
-            int read = read(read_byte);
-
-            if (read < 0) {
-                return -1;
-            } else {
-                return read_byte[0] & 0xFF;
-            }
-        }
-
-        public int available() throws IOException {
-            return (int)getSize() - totalIndex;
-        }
-
-
-        public synchronized void mark(int readlimit) {
-            mark = totalIndex;
-        }
-
-        public boolean markSupported() {
-            return true;
-        }
-
-        public int read(byte[] b, int off, int len) throws IOException {
-            int size = (int)getSize();
-            int total = 0;
-            if (totalIndex >= size) {
-                return -1;
-            }
-            while (total < len && totalIndex < size) {
-                if (currBuffer == null) {
-                    currBuffer = (byte[]) data.get(i);
-                }
-                int copy = Math.min(len - total, BUFFER_SIZE - currIndex);
-                copy = Math.min(copy, size - totalIndex);
-                System.arraycopy(currBuffer, currIndex, b, off, copy);
-                total += copy;
-                currIndex += copy;
-                totalIndex += copy;
-                off += copy;
-                if (currIndex == BUFFER_SIZE) {
-                    i++;
-                    currIndex = 0;
-                    currBuffer = null;
-                }
-            }
-            return total;
-        }
-
-        public int read(byte[] b) throws IOException {
-            return this.read(b, 0, b.length);
-        }
-
-        public synchronized void reset() throws IOException {
-            i = mark / BUFFER_SIZE;
-            currIndex = mark - (i * BUFFER_SIZE);
-            currBuffer = (byte[]) data.get(i);
-            totalIndex = mark;
-        }
-    }
-    
-    List data; // null here indicates the blob is in state NEW
-    int index;
-    byte[] currBuffer;
-    boolean committed;
-    
-    private void init() {
-        data = new ArrayList();
-        addBuffer();
-    }
-    
-    void addBuffer() {
-        currBuffer = new byte[BUFFER_SIZE];
-        data.add(currBuffer);
-        index = 0;
-    }
+    private MemoryBlobChunk firstChunk;
+    private boolean committed;
     
     public long getSize() {
-        if (data == null || !committed) {
+        if (firstChunk == null || !committed) {
             throw new IllegalStateException();
         } else {
-            return (BUFFER_SIZE * (data.size()-1)) + index;
+            long size = 0;
+            MemoryBlobChunk chunk = firstChunk;
+            while (chunk != null) {
+                size += chunk.size;
+                chunk = chunk.nextChunk;
+            }
+            return size;
         }
     }
 
     public OutputStream getOutputStream() {
-        if (data != null || committed) {
+        return internalGetOutputStream();
+    }
+    
+    private MemoryBlobOutputStream internalGetOutputStream() {
+        if (firstChunk != null || committed) {
             throw new IllegalStateException();
         } else {
-            init();
-            return new OutputStreamImpl();
+            return new MemoryBlobOutputStream(this, firstChunk = new MemoryBlobChunk(4096));
         }
     }
 
-    long readFrom(InputStream in, long length, boolean commit) throws StreamCopyException
{
-        if (committed) {
-            throw new IllegalStateException();
-        }
-        if (data == null) {
-            init();
-        }
-        
-        if (length == -1) {
-            length = Long.MAX_VALUE;
-        }
-        long bytesReceived = 0;
-        
-        // Now directly write to the buffers
-        boolean done = false;
-        while (!done) {
-            
-            // Don't get more than will fit in the current buffer
-            int len = (int) Math.min(BUFFER_SIZE - index, length-bytesReceived);
-            
-            // Now get the bytes
-            int bytesRead;
-            try {
-                bytesRead = in.read(currBuffer, index, len);
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.READ, ex);
-            }
-            if (bytesRead >= 0) {
-                bytesReceived += bytesRead;
-                index += bytesRead;
-                if (index >= BUFFER_SIZE) {
-                    addBuffer();
-                }
-                if (bytesReceived >= length) {
-                    done = true;
-                }
-            } else {
-                done = true;
-            }
-        }
-        
-        committed = commit;
-        
-        return bytesReceived;
+    void commit() {
+        committed = true;
     }
-
+    
     public long readFrom(InputStream in) throws StreamCopyException {
-        if (data != null) {
-            throw new IllegalStateException();
+        MemoryBlobOutputStream out = internalGetOutputStream();
+        try {
+            return out.readFrom(in, -1);
+        } finally {
+            out.close();
         }
-        return readFrom(in, -1, true);
     }
 
     public InputStream getInputStream() {
-        if (data == null || !committed) {
+        return getInputStream(true);
+    }
+    
+    public InputStream readOnce() {
+        return getInputStream(false);
+    }
+
+    public InputStream getInputStream(boolean preserve) {
+        if (firstChunk == null || !committed) {
             throw new IllegalStateException();
         }
-        return new InputStreamImpl();
+        InputStream in = new MemoryBlobInputStream(firstChunk);
+        if (!preserve) {
+            firstChunk = null;
+        }
+        return in;
     }
 
     public void writeTo(OutputStream os) throws StreamCopyException {
-        if (data == null || !committed) {
+        if (firstChunk == null || !committed) {
             throw new IllegalStateException();
         }
-        int size = (int)getSize();
+        MemoryBlobChunk chunk = firstChunk;
         try {
-            int numBuffers = data.size();
-            for (int j = 0; j < numBuffers-1; j ++) {
-                os.write( (byte[]) data.get(j), 0, BUFFER_SIZE);
+            while (chunk != null) {
+                if (chunk.size > 0) {
+                    os.write(chunk.buffer, 0, chunk.size);
+                }
+                chunk = chunk.nextChunk;
             }
-            int writeLimit = size - ((numBuffers-1) * BUFFER_SIZE);
-            os.write( (byte[]) data.get(numBuffers-1), 0, writeLimit);
         } catch (IOException ex) {
             throw new StreamCopyException(StreamCopyException.WRITE, ex);
         }
     }
 
     public void release() {
-        data = null;
+        firstChunk = null;
     }
 }

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobInputStream.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobInputStream.java?rev=1679747&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobInputStream.java
(added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobInputStream.java
Sat May 16 16:57:36 2015
@@ -0,0 +1,128 @@
+/*
+ * 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.axiom.blob;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+final class MemoryBlobInputStream extends InputStream {
+    private MemoryBlobChunk chunk;
+    private int index;
+    private MemoryBlobChunk markChunk;
+    private int markIndex;
+    
+    MemoryBlobInputStream(MemoryBlobChunk firstChunk) {
+        chunk = firstChunk;
+    }
+
+    private void updateChunk() {
+        while (chunk != null && index == chunk.size) {
+            chunk = chunk.nextChunk;
+            index = 0;
+        }
+    }
+    
+    @Override
+    public int read(byte[] buffer, int off, int len) throws IOException {
+        int read = 0;
+        while (len > 0) {
+            updateChunk();
+            if (chunk == null) {
+                if (read == 0) {
+                    return -1;
+                } else {
+                    break;
+                }
+            }
+            int c = Math.min(len, chunk.size-index);
+            System.arraycopy(chunk.buffer, index, buffer, off, c);
+            index += c;
+            off += c;
+            len -= c;
+            read += c;
+        }
+        return read;
+    }
+
+    @Override
+    public int read() throws IOException {
+        updateChunk();
+        if (chunk == null) {
+            return -1;
+        } else {
+            return chunk.buffer[index++] & 0xFF;
+        }
+    }
+
+    @Override
+    public boolean markSupported() {
+        return true;
+    }
+
+    @Override
+    public synchronized void mark(int readlimit) {
+        markChunk = chunk;
+        markIndex = index;
+    }
+
+    @Override
+    public synchronized void reset() throws IOException {
+        chunk = markChunk;
+        index = markIndex;
+    }
+
+    @Override
+    public long skip(long n) throws IOException {
+        long skipped = 0;
+        while (n > 0) {
+            updateChunk();
+            if (chunk == null) {
+                break;
+            }
+            int c = (int)Math.min(n, chunk.size-index);
+            index += c;
+            skipped += c;
+            n -= c;
+        }
+        return skipped;
+    }
+
+    @Override
+    public int available() throws IOException {
+        if (chunk == null) {
+            return 0;
+        } else {
+            long available = chunk.size - index;
+            MemoryBlobChunk chunk = this.chunk.nextChunk;
+            while (chunk != null) {
+                available += chunk.size;
+                if (available > Integer.MAX_VALUE) {
+                    return Integer.MAX_VALUE;
+                }
+                chunk = chunk.nextChunk;
+            }
+            return (int)available;
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        chunk = null;
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobInputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobOutputStream.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobOutputStream.java?rev=1679747&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobOutputStream.java
(added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobOutputStream.java
Sat May 16 16:57:36 2015
@@ -0,0 +1,98 @@
+/*
+ * 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.axiom.blob;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.axiom.ext.io.ReadFromSupport;
+import org.apache.axiom.ext.io.StreamCopyException;
+
+final class MemoryBlobOutputStream extends OutputStream implements ReadFromSupport {
+    private final MemoryBlobImpl blob;
+    private MemoryBlobChunk chunk;
+    
+    MemoryBlobOutputStream(MemoryBlobImpl blob, MemoryBlobChunk firstChunk) {
+        this.blob = blob;
+        chunk = firstChunk;
+    }
+    
+    private void updateChunk() {
+        if (chunk.size == chunk.buffer.length) {
+            chunk = chunk.allocateNextChunk();
+        }
+    }
+    
+    @Override
+    public void write(byte[] b, int off, int len) {
+        if (chunk == null) {
+            throw new IllegalStateException();
+        }
+        int total = 0;
+        while (total < len) {
+            updateChunk();
+            int c = Math.min(len-total, chunk.buffer.length-chunk.size);
+            System.arraycopy(b, off, chunk.buffer, chunk.size, c);
+            chunk.size += c;
+            total += c;
+            off += c;
+        }
+    }
+
+    @Override
+    public void write(int b) {
+        if (chunk == null) {
+            throw new IllegalStateException();
+        }
+        updateChunk();
+        chunk.buffer[chunk.size++] = (byte)b;
+    }
+
+    public long readFrom(InputStream in, long length) throws StreamCopyException {
+        if (chunk == null) {
+            throw new IllegalStateException();
+        }
+        long read = 0;
+        long toRead = length == -1 ? Long.MAX_VALUE : length;
+        while (toRead > 0) {
+            updateChunk();
+            int c;
+            try {
+                c = in.read(chunk.buffer, chunk.size,
+                        (int)Math.min(toRead, chunk.buffer.length-chunk.size));
+            } catch (IOException ex) {
+                throw new StreamCopyException(StreamCopyException.READ, ex);
+            }
+            if (c == -1) {
+                break;
+            }
+            chunk.size += c;
+            read += c;
+            toRead -= c;
+        }
+        return read;
+    }
+    
+    @Override
+    public void close() {
+        blob.commit();
+        chunk = null;
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message