Skip to content

Commit

Permalink
[performance] move storage binary resources from dbx files to filesys…
Browse files Browse the repository at this point in the history
…tem.

Yields into performance increase for (concurrent) access of binary files (=queries).
Internally binary resources are dealt as Streams 
Patch created by Alex Milowski

svn path=/trunk/eXist/; revision=8222
  • Loading branch information
dizzzz committed Oct 7, 2008
1 parent e6f3637 commit ac5472a
Show file tree
Hide file tree
Showing 26 changed files with 879 additions and 79 deletions.
8 changes: 7 additions & 1 deletion extensions/fluent/src/org/exist/fluent/Document.java
Expand Up @@ -322,9 +322,15 @@ private DocumentImpl moveOrCopy(Folder destination, Name name, boolean copy) {
public String contentsAsString() { public String contentsAsString() {
DBBroker broker = db.acquireBroker(); DBBroker broker = db.acquireBroker();
try { try {
return new String(broker.getBinaryResource((BinaryDocument) doc), db.defaultCharacterEncoding); InputStream is = broker.getBinaryResource((BinaryDocument) doc);
byte [] data = new byte[(int)broker.getBinaryResourceSize((BinaryDocument) doc)];
is.read(data);
is.close();
return new String(data, db.defaultCharacterEncoding);
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new DatabaseException(e); throw new DatabaseException(e);
} catch (IOException e) {
throw new DatabaseException(e);
} finally { } finally {
db.releaseBroker(broker); db.releaseBroker(broker);
} }
Expand Down
20 changes: 20 additions & 0 deletions extensions/fluent/test/src/org/exist/fluent/DocumentTest.java
Expand Up @@ -36,6 +36,16 @@ public class DocumentTest extends DatabaseTestCase {
assertEquals("helloworld", original.contentsAsString()); assertEquals("helloworld", original.contentsAsString());
assertEquals("helloworld", copy.contentsAsString()); assertEquals("helloworld", copy.contentsAsString());
} }

@Test public void copy2() {
Folder c1 = db.createFolder("/c1"), c2 = db.createFolder("/c2");
Document original = c1.documents().load(Name.create("original.xml"), Source.xml("<original/>"));
Document copy = original.copy(c2, Name.keepCreate());
assertEquals(1, c1.documents().size());
assertEquals(1, c2.documents().size());
assertEquals("<original/>", original.contentsAsString());
assertEquals("<original/>", copy.contentsAsString());
}


@Test public void move1() { @Test public void move1() {
Folder c1 = db.createFolder("/c1"), c2 = db.createFolder("/c2"); Folder c1 = db.createFolder("/c1"), c2 = db.createFolder("/c2");
Expand All @@ -46,5 +56,15 @@ public class DocumentTest extends DatabaseTestCase {
assertEquals("/c2/original", doc.path()); assertEquals("/c2/original", doc.path());
assertEquals("helloworld", doc.contentsAsString()); assertEquals("helloworld", doc.contentsAsString());
} }

@Test public void move2() {
Folder c1 = db.createFolder("/c1"), c2 = db.createFolder("/c2");
Document doc = c1.documents().load(Name.create("original.xml"), Source.xml("<original/>"));
doc.move(c2, Name.keepCreate());
assertEquals(0, c1.documents().size());
assertEquals(1, c2.documents().size());
assertEquals("/c2/original.xml", doc.path());
assertEquals("<original/>", doc.contentsAsString());
}


} }
Expand Up @@ -21,6 +21,7 @@
*/ */
package org.exist.xquery.modules.compression; package org.exist.xquery.modules.compression;


import java.io.InputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
Expand Down Expand Up @@ -210,9 +211,13 @@ private void tarResource(TarOutputStream tos, DocumentImpl doc,
tos.write(strDoc.getBytes()); tos.write(strDoc.getBytes());
} else if (doc.getResourceType() == DocumentImpl.BINARY_FILE) { } else if (doc.getResourceType() == DocumentImpl.BINARY_FILE) {
// binary file // binary file
byte[] data = context.getBroker().getBinaryResource( InputStream is = context.getBroker().getBinaryResource((BinaryDocument)doc);
(BinaryDocument) doc); byte[] data = new byte[16384];
tos.write(data); int len = 0;
while ((len=is.read(data,0,data.length))>0) {
tos.write(data,0,len);
}
is.close();
} }


// close the entry in the Tar // close the entry in the Tar
Expand Down Expand Up @@ -261,4 +266,4 @@ private void tarCollection(TarOutputStream tos, Collection col,
tarCollection(tos, childCol, useHierarchy, stripOffset); tarCollection(tos, childCol, useHierarchy, stripOffset);
} }
} }
} }
Expand Up @@ -22,6 +22,7 @@
package org.exist.xquery.modules.compression; package org.exist.xquery.modules.compression;


import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
Expand Down Expand Up @@ -210,9 +211,14 @@ private void zipResource(ZipOutputStream zos, DocumentImpl doc,
zos.write(strDoc.getBytes()); zos.write(strDoc.getBytes());
} else if (doc.getResourceType() == DocumentImpl.BINARY_FILE) { } else if (doc.getResourceType() == DocumentImpl.BINARY_FILE) {
// binary file // binary file
byte[] data = context.getBroker().getBinaryResource( InputStream is = context.getBroker().getBinaryResource(
(BinaryDocument) doc); (BinaryDocument) doc);
zos.write(data); byte [] data = new byte[16384];
int len;
while ((len=is.read(data))>0) {
zos.write(data,0,len);
}
is.close();
} }


// close the entry in the Zip // close the entry in the Zip
Expand Down
Expand Up @@ -2,6 +2,7 @@


import java.awt.Image; import java.awt.Image;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
Expand Down Expand Up @@ -213,11 +214,10 @@ public boolean accept(File dir, String name) {
binImage = (BinaryDocument) docImage; binImage = (BinaryDocument) docImage;


// get a byte array representing the image // get a byte array representing the image
imgData = dbbroker.getBinaryResource(binImage);


try { try {
image = ImageIO.read(new ByteArrayInputStream( InputStream is = dbbroker.getBinaryResource(binImage);
imgData)); image = ImageIO.read(is);
} catch (IOException ioe) { } catch (IOException ioe) {
throw new XPathException(getASTNode(),ioe.getMessage()); throw new XPathException(getASTNode(),ioe.getMessage());
} }
Expand Down
4 changes: 4 additions & 0 deletions src/org/exist/cluster/ClusterCollection.java
Expand Up @@ -165,7 +165,11 @@ public void store(Txn transaction, DBBroker broker, IndexInfo info, InputSource
public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
XmldbURI name, byte[] data, String mimeType) throws EXistException, XmldbURI name, byte[] data, String mimeType) throws EXistException,
PermissionDeniedException, LockException, TriggerException { PermissionDeniedException, LockException, TriggerException {
try {
return collection.addBinaryResource(transaction, broker, name, data, mimeType); return collection.addBinaryResource(transaction, broker, name, data, mimeType);
} catch (IOException ex) {
throw new EXistException("Cannot add binary due to I/O error.",ex);
}
} }


public Lock getLock() { public Lock getLock() {
Expand Down
34 changes: 28 additions & 6 deletions src/org/exist/collections/Collection.java
Expand Up @@ -865,7 +865,11 @@ public void removeBinaryResource(Txn transaction, DBBroker broker, DocumentImpl
if (trigger != null) if (trigger != null)
trigger.prepare(Trigger.REMOVE_DOCUMENT_EVENT, broker, transaction, doc.getURI(), doc); trigger.prepare(Trigger.REMOVE_DOCUMENT_EVENT, broker, transaction, doc.getURI(), doc);


broker.removeBinaryResource(transaction, (BinaryDocument) doc); try {
broker.removeBinaryResource(transaction, (BinaryDocument) doc);
} catch (IOException ex) {
throw new PermissionDeniedException("Cannot delete file.");
}
documents.remove(doc.getFileURI().getRawCollectionPath()); documents.remove(doc.getFileURI().getRawCollectionPath());


if (trigger != null) { if (trigger != null) {
Expand Down Expand Up @@ -1361,29 +1365,29 @@ private DocumentTrigger setupTriggers(DBBroker broker, XmldbURI docUri, boolean
// Blob // Blob
public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
XmldbURI docUri, byte[] data, String mimeType) XmldbURI docUri, byte[] data, String mimeType)
throws EXistException, PermissionDeniedException, LockException, TriggerException { throws EXistException, PermissionDeniedException, LockException, TriggerException,IOException {
return addBinaryResource(transaction, broker, docUri, data, mimeType, null, null); return addBinaryResource(transaction, broker, docUri, data, mimeType, null, null);
} }


// Blob // Blob
public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
XmldbURI docUri, byte[] data, String mimeType, Date created, Date modified) XmldbURI docUri, byte[] data, String mimeType, Date created, Date modified)
throws EXistException, PermissionDeniedException, LockException, TriggerException { throws EXistException, PermissionDeniedException, LockException, TriggerException,IOException {
return addBinaryResource(transaction, broker, docUri, return addBinaryResource(transaction, broker, docUri,
new ByteArrayInputStream(data), mimeType, data.length, created, modified); new ByteArrayInputStream(data), mimeType, data.length, created, modified);
} }


// Streaming // Streaming
public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
XmldbURI docUri, InputStream is, String mimeType, int size) XmldbURI docUri, InputStream is, String mimeType, int size)
throws EXistException, PermissionDeniedException, LockException, TriggerException { throws EXistException, PermissionDeniedException, LockException, TriggerException,IOException {
return addBinaryResource(transaction, broker, docUri, is, mimeType, size, null, null); return addBinaryResource(transaction, broker, docUri, is, mimeType, size, null, null);
} }


// Streaming // Streaming
public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker, public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
XmldbURI docUri, InputStream is, String mimeType, int size, Date created, Date modified) XmldbURI docUri, InputStream is, String mimeType, int size, Date created, Date modified)
throws EXistException, PermissionDeniedException, LockException, TriggerException { throws EXistException, PermissionDeniedException, LockException, TriggerException,IOException {


if (broker.isReadOnly()) if (broker.isReadOnly())
throw new PermissionDeniedException("Database is read-only"); throw new PermissionDeniedException("Database is read-only");
Expand All @@ -1400,6 +1404,7 @@ public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
checkPermissions(transaction, broker, oldDoc); checkPermissions(transaction, broker, oldDoc);
DocumentTrigger trigger = null; DocumentTrigger trigger = null;
int event = 0; int event = 0;
/*
if (triggersEnabled) { if (triggersEnabled) {
CollectionConfiguration config = getConfiguration(broker); CollectionConfiguration config = getConfiguration(broker);
if (config != null) { if (config != null) {
Expand All @@ -1414,6 +1419,7 @@ public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
} }
} }
} }
*/


manageDocumentInformation(broker, oldDoc, blob ); manageDocumentInformation(broker, oldDoc, blob );
DocumentMetadata metadata = blob.getMetadata(); DocumentMetadata metadata = blob.getMetadata();
Expand All @@ -1438,8 +1444,24 @@ public BinaryDocument addBinaryResource(Txn transaction, DBBroker broker,
addDocument(transaction, broker, blob); addDocument(transaction, broker, blob);


broker.storeXMLResource(transaction, blob); broker.storeXMLResource(transaction, blob);
if (triggersEnabled) {
CollectionConfiguration config = getConfiguration(broker);
if (config != null) {
event = oldDoc != null ? Trigger.UPDATE_DOCUMENT_EVENT : Trigger.STORE_DOCUMENT_EVENT;
try {
trigger = (DocumentTrigger) config.newTrigger(event, broker, this);
} catch (CollectionConfigurationException e) {
LOG.debug("An error occurred while initializing a trigger for collection " + getURI() + ": " + e.getMessage(), e);
}
if (trigger != null) {
trigger.prepare(event, broker, transaction, blob.getURI(), blob);
}
}
}



broker.closeDocument(); // This is no longer needed as the dom.dbx isn't used
//broker.closeDocument();


if (trigger != null) { if (trigger != null) {
trigger.finish(event, broker, transaction, blob.getURI(), blob); trigger.finish(event, broker, transaction, blob.getURI(), blob);
Expand Down
11 changes: 9 additions & 2 deletions src/org/exist/collections/triggers/XQueryTrigger.java
@@ -1,6 +1,7 @@
package org.exist.collections.triggers; package org.exist.collections.triggers;


import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
Expand Down Expand Up @@ -219,7 +220,10 @@ else if (existingDocument instanceof BinaryDocument)
{ {
//binary document //binary document
BinaryDocument bin = (BinaryDocument)existingDocument; BinaryDocument bin = (BinaryDocument)existingDocument;
byte[] data = context.getBroker().getBinaryResource(bin); InputStream is = broker.getBinaryResource(bin);
byte [] data = new byte[(int)broker.getBinaryResourceSize(bin)];
is.read(data);
is.close();


context.declareVariable(bindingPrefix + "document", new Base64Binary(data)); context.declareVariable(bindingPrefix + "document", new Base64Binary(data));
} }
Expand Down Expand Up @@ -302,7 +306,10 @@ else if (document instanceof BinaryDocument)
{ {
//Binary document //Binary document
BinaryDocument bin = (BinaryDocument)document; BinaryDocument bin = (BinaryDocument)document;
byte[] data = context.getBroker().getBinaryResource(bin); InputStream is = broker.getBinaryResource(bin);
byte [] data = new byte[(int)broker.getBinaryResourceSize(bin)];
is.read(data);
is.close();


context.declareVariable(bindingPrefix + "document", new Base64Binary(data)); context.declareVariable(bindingPrefix + "document", new Base64Binary(data));
} }
Expand Down
15 changes: 12 additions & 3 deletions src/org/exist/http/SOAPServer.java
Expand Up @@ -1309,9 +1309,18 @@ private BinaryDocument getXQWS(DBBroker broker, String path) throws PermissionDe
*/ */
private byte[] getXQWSData(DBBroker broker, BinaryDocument docXQWS) private byte[] getXQWSData(DBBroker broker, BinaryDocument docXQWS)
{ {
byte[] data = broker.getBinaryResource(docXQWS); try {

InputStream is = broker.getBinaryResource(docXQWS);
return data; byte [] data = new byte[(int)broker.getBinaryResourceSize(docXQWS)];
is.read(data);
is.close();

return data;
} catch (IOException ex) {
// TODO: where should this go?
ex.printStackTrace();
}
return null;
} }


/** /**
Expand Down
14 changes: 13 additions & 1 deletion src/org/exist/soap/AdminSoapBindingImpl.java
@@ -1,4 +1,12 @@
package org.exist.soap; package org.exist.soap;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URISyntaxException;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.Vector;


import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.exist.EXistException; import org.exist.EXistException;
Expand Down Expand Up @@ -449,7 +457,11 @@ public byte[] getBinaryResource(java.lang.String sessionId, XmldbURI name) throw
+ " is not a binary resource"); + " is not a binary resource");
if(!doc.getPermissions().validate(session.getUser(), Permission.READ)) if(!doc.getPermissions().validate(session.getUser(), Permission.READ))
throw new PermissionDeniedException("Insufficient privileges to read resource"); throw new PermissionDeniedException("Insufficient privileges to read resource");
return broker.getBinaryResource( (BinaryDocument) doc ); InputStream is = broker.getBinaryResource((BinaryDocument) doc);
byte [] data = new byte[(int)broker.getBinaryResourceSize((BinaryDocument) doc)];
is.read(data);
is.close();
return data;
} catch (Exception ex) { } catch (Exception ex) {
throw new RemoteException(ex.getMessage()); throw new RemoteException(ex.getMessage());
} finally { } finally {
Expand Down
17 changes: 11 additions & 6 deletions src/org/exist/source/DBSource.java
Expand Up @@ -21,6 +21,7 @@
*/ */
package org.exist.source; package org.exist.source;


import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
Expand Down Expand Up @@ -108,18 +109,22 @@ public int isValid(Source other) {
* @see org.exist.source.Source#getReader() * @see org.exist.source.Source#getReader()
*/ */
public Reader getReader() throws IOException { public Reader getReader() throws IOException {
byte[] data = broker.getBinaryResource(doc); InputStream is = broker.getBinaryResource(doc);
ByteArrayInputStream is = new ByteArrayInputStream(data); BufferedInputStream bis = new BufferedInputStream(is);
checkEncoding(is); bis.mark(64);
is.reset(); checkEncoding(bis);
return new InputStreamReader(is, encoding); bis.reset();
return new InputStreamReader(bis, encoding);
} }


/* (non-Javadoc) /* (non-Javadoc)
* @see org.exist.source.Source#getContent() * @see org.exist.source.Source#getContent()
*/ */
public String getContent() throws IOException { public String getContent() throws IOException {
byte[] data = broker.getBinaryResource(doc); InputStream raw = broker.getBinaryResource(doc);
byte [] data = new byte[(int)broker.getBinaryResourceSize(doc)];
raw.read(data);
raw.close();
ByteArrayInputStream is = new ByteArrayInputStream(data); ByteArrayInputStream is = new ByteArrayInputStream(data);
checkEncoding(is); checkEncoding(is);
return new String(data, encoding); return new String(data, encoding);
Expand Down

0 comments on commit ac5472a

Please sign in to comment.