You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2006/11/24 15:40:26 UTC
svn commit: r478892 [2/2] - in
/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core:
fs/db/ persistence/db/
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java?view=diff&rev=478892&r1=478891&r2=478892
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java Fri Nov 24 06:40:22 2006
@@ -55,8 +55,8 @@
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
-import java.util.List;
-import java.util.LinkedList;
+import java.util.HashMap;
+import java.util.Iterator;
/**
* Abstract base class for database persistence managers. This class
@@ -91,37 +91,45 @@
// jdbc connection
protected Connection con;
- // the list of prepared statements, used in close()
- private List preparedStatements;
+ // internal flag governing whether an automatic reconnect should be
+ // attempted after a SQLException had been encountered
+ protected boolean autoReconnect = true;
+ // time to sleep in ms before a reconnect is attempted
+ protected static final int SLEEP_BEFORE_RECONNECT = 10000;
+
+ // the map of prepared statements (key: sql stmt, value: prepared stmt)
+ private HashMap preparedStatements = new HashMap();
+
+ // SQL statements for NodeState management
+ protected String nodeStateInsertSQL;
+ protected String nodeStateUpdateSQL;
+ protected String nodeStateSelectSQL;
+ protected String nodeStateSelectExistSQL;
+ protected String nodeStateDeleteSQL;
+
+ // SQL statements for PropertyState management
+ protected String propertyStateInsertSQL;
+ protected String propertyStateUpdateSQL;
+ protected String propertyStateSelectSQL;
+ protected String propertyStateSelectExistSQL;
+ protected String propertyStateDeleteSQL;
+
+ // SQL statements for NodeReference management
+ protected String nodeReferenceInsertSQL;
+ protected String nodeReferenceUpdateSQL;
+ protected String nodeReferenceSelectSQL;
+ protected String nodeReferenceSelectExistSQL;
+ protected String nodeReferenceDeleteSQL;
- // shared prepared statements for NodeState management
- protected PreparedStatement nodeStateInsert;
- protected PreparedStatement nodeStateUpdate;
- protected PreparedStatement nodeStateSelect;
- protected PreparedStatement nodeStateSelectExist;
- protected PreparedStatement nodeStateDelete;
-
- // shared prepared statements for PropertyState management
- protected PreparedStatement propertyStateInsert;
- protected PreparedStatement propertyStateUpdate;
- protected PreparedStatement propertyStateSelect;
- protected PreparedStatement propertyStateSelectExist;
- protected PreparedStatement propertyStateDelete;
-
- // shared prepared statements for NodeReference management
- protected PreparedStatement nodeReferenceInsert;
- protected PreparedStatement nodeReferenceUpdate;
- protected PreparedStatement nodeReferenceSelect;
- protected PreparedStatement nodeReferenceSelectExist;
- protected PreparedStatement nodeReferenceDelete;
-
- // shared prepared statements for BLOB management
+ // SQL statements for BLOB management
// (if <code>externalBLOBs==false</code>)
- protected PreparedStatement blobInsert;
- protected PreparedStatement blobUpdate;
- protected PreparedStatement blobSelect;
- protected PreparedStatement blobSelectExist;
- protected PreparedStatement blobDelete;
+ protected String blobInsertSQL;
+ protected String blobUpdateSQL;
+ protected String blobSelectSQL;
+ protected String blobSelectExistSQL;
+ protected String blobDeleteSQL;
+
+
/**
* file system where BLOB data is stored
@@ -193,8 +201,11 @@
// check if schema objects exist and create them if necessary
checkSchema();
+ // build sql statements
+ buildSQLStatements();
+
// prepare statements
- preparedStatements = initPreparedStatements();
+ initPreparedStatements();
if (externalBLOBs) {
/**
@@ -226,12 +237,10 @@
try {
// close shared prepared statements
- if (preparedStatements != null) {
- while (!preparedStatements.isEmpty()) {
- closeStatement((PreparedStatement) preparedStatements.remove(0));
- }
+ for (Iterator it = preparedStatements.values().iterator(); it.hasNext(); ) {
+ closeStatement((PreparedStatement) it.next());
}
- preparedStatements = null;
+ preparedStatements.clear();
if (externalBLOBs) {
// close BLOB file system
@@ -253,12 +262,39 @@
*/
public synchronized void store(ChangeLog changeLog)
throws ItemStateException {
- ItemStateException ise = null;
+ // temporarily disable automatic reconnect feature
+ // since the changes need to be persisted atomically
+ autoReconnect = false;
try {
- super.store(changeLog);
- } catch (ItemStateException e) {
- ise = e;
- } finally {
+ ItemStateException ise = null;
+ // number of attempts to store the changes
+ int trials = 2;
+ while (true) {
+ try {
+ super.store(changeLog);
+ break;
+ } catch (ItemStateException e) {
+ // catch exception and fall through...
+ ise = e;
+ }
+
+ if (ise != null && ise.getCause() instanceof SQLException
+ && --trials > 0) {
+ // a SQLException has been thrown, try to reconnect
+ log.warn("storing changes failed, about to reconnect...", ise.getCause());
+
+ // try to reconnect
+ if (reestablishConnection()) {
+ // now let's give it another try
+ ise = null;
+ continue;
+ } else {
+ // reconnect failed, proceed with error processing
+ break;
+ }
+ }
+ }
+
if (ise == null) {
// storing the changes succeeded, now commit the changes
try {
@@ -279,6 +315,9 @@
// re-throw original exception
throw ise;
}
+ } finally {
+ // re-enable automatic reconnect feature
+ autoReconnect = true;
}
}
@@ -291,13 +330,11 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = nodeStateSelect;
- synchronized (stmt) {
+ synchronized (nodeStateSelectSQL) {
ResultSet rs = null;
InputStream in = null;
try {
- stmt.setString(1, id.toString());
- stmt.execute();
+ Statement stmt = executeStmt(nodeStateSelectSQL, new Object[]{id.toString()});
rs = stmt.getResultSet();
if (!rs.next()) {
throw new NoSuchItemStateException(id.toString());
@@ -318,7 +355,6 @@
} finally {
closeStream(in);
closeResultSet(rs);
- resetStatement(stmt);
}
}
}
@@ -332,13 +368,11 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = propertyStateSelect;
- synchronized (stmt) {
+ synchronized (propertyStateSelectSQL) {
ResultSet rs = null;
InputStream in = null;
try {
- stmt.setString(1, id.toString());
- stmt.execute();
+ Statement stmt = executeStmt(propertyStateSelectSQL, new Object[]{id.toString()});
rs = stmt.getResultSet();
if (!rs.next()) {
throw new NoSuchItemStateException(id.toString());
@@ -359,7 +393,6 @@
} finally {
closeStream(in);
closeResultSet(rs);
- resetStatement(stmt);
}
}
}
@@ -381,7 +414,7 @@
// check if insert or update
boolean update = state.getStatus() != ItemState.STATUS_NEW;
//boolean update = exists(state.getId());
- PreparedStatement stmt = (update) ? nodeStateUpdate : nodeStateInsert;
+ String sql = (update) ? nodeStateUpdateSQL : nodeStateInsertSQL;
try {
ByteArrayOutputStream out =
@@ -390,11 +423,8 @@
Serializer.serialize(state, out);
// we are synchronized on this instance, therefore we do not
- // not have to additionally synchronize on the preparedStatement
-
- stmt.setBytes(1, out.toByteArray());
- stmt.setString(2, state.getNodeId().toString());
- stmt.executeUpdate();
+ // not have to additionally synchronize on the sql statement
+ executeStmt(sql, new Object[]{out.toByteArray(), state.getNodeId().toString()});
// there's no need to close a ByteArrayOutputStream
//out.close();
@@ -402,8 +432,6 @@
String msg = "failed to write node state: " + state.getNodeId();
log.error(msg, e);
throw new ItemStateException(msg, e);
- } finally {
- resetStatement(stmt);
}
}
@@ -425,7 +453,7 @@
// check if insert or update
boolean update = state.getStatus() != ItemState.STATUS_NEW;
//boolean update = exists(state.getId());
- PreparedStatement stmt = (update) ? propertyStateUpdate : propertyStateInsert;
+ String sql = (update) ? propertyStateUpdateSQL : propertyStateInsertSQL;
try {
ByteArrayOutputStream out =
@@ -434,11 +462,8 @@
Serializer.serialize(state, out, blobStore);
// we are synchronized on this instance, therefore we do not
- // not have to additionally synchronize on the preparedStatement
-
- stmt.setBytes(1, out.toByteArray());
- stmt.setString(2, state.getPropertyId().toString());
- stmt.executeUpdate();
+ // not have to additionally synchronize on the sql statement
+ executeStmt(sql, new Object[]{out.toByteArray(), state.getPropertyId().toString()});
// there's no need to close a ByteArrayOutputStream
//out.close();
@@ -446,8 +471,6 @@
String msg = "failed to write property state: " + state.getPropertyId();
log.error(msg, e);
throw new ItemStateException(msg, e);
- } finally {
- resetStatement(stmt);
}
}
@@ -460,16 +483,14 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = nodeStateDelete;
try {
- stmt.setString(1, state.getNodeId().toString());
- stmt.executeUpdate();
+ // we are synchronized on this instance, therefore we do not
+ // not have to additionally synchronize on the sql statement
+ executeStmt(nodeStateDeleteSQL, new Object[]{state.getNodeId().toString()});
} catch (Exception e) {
String msg = "failed to delete node state: " + state.getNodeId();
log.error(msg, e);
throw new ItemStateException(msg, e);
- } finally {
- resetStatement(stmt);
}
}
@@ -504,16 +525,14 @@
}
}
- PreparedStatement stmt = propertyStateDelete;
try {
- stmt.setString(1, state.getPropertyId().toString());
- stmt.executeUpdate();
+ // we are synchronized on this instance, therefore we do not
+ // not have to additionally synchronize on the sql statement
+ executeStmt(propertyStateDeleteSQL, new Object[]{state.getPropertyId().toString()});
} catch (Exception e) {
String msg = "failed to delete property state: " + state.getPropertyId();
log.error(msg, e);
throw new ItemStateException(msg, e);
- } finally {
- resetStatement(stmt);
}
}
@@ -526,13 +545,12 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = nodeReferenceSelect;
- synchronized (stmt) {
+ synchronized (nodeReferenceSelectSQL) {
ResultSet rs = null;
InputStream in = null;
try {
- stmt.setString(1, targetId.toString());
- stmt.execute();
+ Statement stmt = executeStmt(
+ nodeReferenceSelectSQL, new Object[]{targetId.toString()});
rs = stmt.getResultSet();
if (!rs.next()) {
throw new NoSuchItemStateException(targetId.toString());
@@ -553,7 +571,6 @@
} finally {
closeStream(in);
closeResultSet(rs);
- resetStatement(stmt);
}
}
}
@@ -575,7 +592,7 @@
// check if insert or update
boolean update = exists(refs.getId());
- PreparedStatement stmt = (update) ? nodeReferenceUpdate : nodeReferenceInsert;
+ String sql = (update) ? nodeReferenceUpdateSQL : nodeReferenceInsertSQL;
try {
ByteArrayOutputStream out =
@@ -584,11 +601,8 @@
Serializer.serialize(refs, out);
// we are synchronized on this instance, therefore we do not
- // not have to additionally synchronize on the preparedStatement
-
- stmt.setBytes(1, out.toByteArray());
- stmt.setString(2, refs.getId().toString());
- stmt.executeUpdate();
+ // not have to additionally synchronize on the sql statement
+ executeStmt(sql, new Object[]{out.toByteArray(), refs.getId().toString()});
// there's no need to close a ByteArrayOutputStream
//out.close();
@@ -596,8 +610,6 @@
String msg = "failed to write node references: " + refs.getId();
log.error(msg, e);
throw new ItemStateException(msg, e);
- } finally {
- resetStatement(stmt);
}
}
@@ -610,16 +622,14 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = nodeReferenceDelete;
try {
- stmt.setString(1, refs.getId().toString());
- stmt.executeUpdate();
+ // we are synchronized on this instance, therefore we do not
+ // not have to additionally synchronize on the sql statement
+ executeStmt(nodeReferenceDeleteSQL, new Object[]{refs.getId().toString()});
} catch (Exception e) {
String msg = "failed to delete node references: " + refs.getId();
log.error(msg, e);
throw new ItemStateException(msg, e);
- } finally {
- resetStatement(stmt);
}
}
@@ -631,12 +641,10 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = nodeStateSelectExist;
- synchronized (stmt) {
+ synchronized (nodeStateSelectExistSQL) {
ResultSet rs = null;
try {
- stmt.setString(1, id.toString());
- stmt.execute();
+ Statement stmt = executeStmt(nodeStateSelectExistSQL, new Object[]{id.toString()});
rs = stmt.getResultSet();
// a node state exists if the result has at least one entry
@@ -647,7 +655,6 @@
throw new ItemStateException(msg, e);
} finally {
closeResultSet(rs);
- resetStatement(stmt);
}
}
}
@@ -660,12 +667,11 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = propertyStateSelectExist;
- synchronized (stmt) {
+ synchronized (propertyStateSelectExistSQL) {
ResultSet rs = null;
try {
- stmt.setString(1, id.toString());
- stmt.execute();
+ Statement stmt = executeStmt(
+ propertyStateSelectExistSQL, new Object[]{id.toString()});
rs = stmt.getResultSet();
// a property state exists if the result has at least one entry
@@ -676,7 +682,6 @@
throw new ItemStateException(msg, e);
} finally {
closeResultSet(rs);
- resetStatement(stmt);
}
}
}
@@ -689,12 +694,11 @@
throw new IllegalStateException("not initialized");
}
- PreparedStatement stmt = nodeReferenceSelectExist;
- synchronized (stmt) {
+ synchronized (nodeReferenceSelectExistSQL) {
ResultSet rs = null;
try {
- stmt.setString(1, targetId.toString());
- stmt.execute();
+ Statement stmt = executeStmt(
+ nodeReferenceSelectExistSQL, new Object[]{targetId.toString()});
rs = stmt.getResultSet();
// a reference exists if the result has at least one entry
@@ -706,7 +710,6 @@
throw new ItemStateException(msg, e);
} finally {
closeResultSet(rs);
- resetStatement(stmt);
}
}
}
@@ -763,6 +766,110 @@
}
/**
+ * Re-establishes the database connection. This method is called by
+ * {@link #store(ChangeLog)} and {@link #executeStmt(String, Object[])}
+ * after a <code>SQLException</code> had been encountered.
+ * @return true if the connection could be successfully re-established,
+ * false otherwise.
+ */
+ protected synchronized boolean reestablishConnection() {
+ // in any case try to shut down current connection
+ // gracefully in order to avoid potential memory leaks
+
+ // close shared prepared statements
+ for (Iterator it = preparedStatements.values().iterator(); it.hasNext(); ) {
+ closeStatement((PreparedStatement) it.next());
+ }
+ preparedStatements.clear();
+ try {
+ closeConnection(con);
+ } catch (Exception ignore) {
+ }
+
+ // sleep for a while to give database a chance
+ // to restart before a reconnect is attempted
+
+ try {
+ Thread.sleep(SLEEP_BEFORE_RECONNECT);
+ } catch (InterruptedException ignore) {
+ }
+
+ // now try to re-establish connection
+
+ try {
+ initConnection();
+ initPreparedStatements();
+ return true;
+ } catch (Exception e) {
+ log.error("failed to re-establish connection", e);
+ // reconnect failed
+ return false;
+ }
+ }
+
+ /**
+ * Executes the given SQL statement with the specified parameters.
+ * If a <code>SQLException</code> is encountered and
+ * <code>autoReconnect==true</code> <i>one</i> attempt is made to re-establish
+ * the database connection and re-execute the statement.
+ *
+ * @param sql statement to execute
+ * @param params parameters to set
+ * @return the <code>Statement</code> object that had been executed
+ * @throws SQLException if an error occurs
+ */
+ protected Statement executeStmt(String sql, Object[] params)
+ throws SQLException {
+ int trials = autoReconnect ? 2 : 1;
+ while (true) {
+ PreparedStatement stmt = (PreparedStatement) preparedStatements.get(sql);
+ try {
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof SizedInputStream) {
+ SizedInputStream in = (SizedInputStream) params[i];
+ stmt.setBinaryStream(i + 1, in, (int) in.getSize());
+ } else {
+ stmt.setObject(i + 1, params[i]);
+ }
+ }
+ stmt.execute();
+ resetStatement(stmt);
+ return stmt;
+ } catch (SQLException se) {
+ if (--trials == 0) {
+ // no more trials, re-throw
+ throw se;
+ }
+ log.warn("execute failed, about to reconnect...", se.getMessage());
+
+ // try to reconnect
+ if (reestablishConnection()) {
+ // reconnect succeeded; check whether it's possible to
+ // re-execute the prepared stmt with the given parameters
+ for (int i = 0; i < params.length; i++) {
+ if (params[i] instanceof SizedInputStream) {
+ SizedInputStream in = (SizedInputStream) params[i];
+ if (in.isConsumed()) {
+ // we're unable to re-execute the prepared stmt
+ // since an InputStream paramater has already
+ // been 'consumed';
+ // re-throw previous SQLException
+ throw se;
+ }
+ }
+ }
+
+ // try again to execute the statement
+ continue;
+ } else {
+ // reconnect failed, re-throw previous SQLException
+ throw se;
+ }
+ }
+ }
+ }
+
+ /**
* Resets the given <code>PreparedStatement</code> by clearing the parameters
* and warnings contained.
* <p/>
@@ -917,85 +1024,147 @@
}
/**
- * Initializes the prepared statements and returns them in a list. please
- * note that this list is used to close the statements in the {@link #close()}
- * call.
- *
- * @return the list of prepared statements
- * @throws SQLException
+ * Builds the SQL statements
*/
- protected List initPreparedStatements() throws SQLException {
- List stmts = new LinkedList();
+ protected void buildSQLStatements() {
+ nodeStateInsertSQL = "insert into "
+ + schemaObjectPrefix + "NODE (NODE_DATA, NODE_ID) values (?, ?)";
+
+ nodeStateUpdateSQL = "update "
+ + schemaObjectPrefix + "NODE set NODE_DATA = ? where NODE_ID = ?";
+ nodeStateSelectSQL = "select NODE_DATA from "
+ + schemaObjectPrefix + "NODE where NODE_ID = ?";
+ nodeStateSelectExistSQL = "select 1 from "
+ + schemaObjectPrefix + "NODE where NODE_ID = ?";
+ nodeStateDeleteSQL = "delete from "
+ + schemaObjectPrefix + "NODE where NODE_ID = ?";
+
+ propertyStateInsertSQL = "insert into "
+ + schemaObjectPrefix + "PROP (PROP_DATA, PROP_ID) values (?, ?)";
+ propertyStateUpdateSQL = "update "
+ + schemaObjectPrefix + "PROP set PROP_DATA = ? where PROP_ID = ?";
+ propertyStateSelectSQL = "select PROP_DATA from "
+ + schemaObjectPrefix + "PROP where PROP_ID = ?";
+ propertyStateSelectExistSQL = "select 1 from "
+ + schemaObjectPrefix + "PROP where PROP_ID = ?";
+ propertyStateDeleteSQL = "delete from "
+ + schemaObjectPrefix + "PROP where PROP_ID = ?";
+
+ nodeReferenceInsertSQL = "insert into "
+ + schemaObjectPrefix + "REFS (REFS_DATA, NODE_ID) values (?, ?)";
+ nodeReferenceUpdateSQL = "update "
+ + schemaObjectPrefix + "REFS set REFS_DATA = ? where NODE_ID = ?";
+ nodeReferenceSelectSQL = "select REFS_DATA from "
+ + schemaObjectPrefix + "REFS where NODE_ID = ?";
+ nodeReferenceSelectExistSQL = "select 1 from "
+ + schemaObjectPrefix + "REFS where NODE_ID = ?";
+ nodeReferenceDeleteSQL = "delete from "
+ + schemaObjectPrefix + "REFS where NODE_ID = ?";
+
+ if (!externalBLOBs) {
+ blobInsertSQL = "insert into "
+ + schemaObjectPrefix + "BINVAL (BINVAL_DATA, BINVAL_ID) values (?, ?)";
+ blobUpdateSQL = "update "
+ + schemaObjectPrefix + "BINVAL set BINVAL_DATA = ? where BINVAL_ID = ?";
+ blobSelectSQL =
+ "select BINVAL_DATA from "
+ + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?";
+ blobSelectExistSQL =
+ "select 1 from "
+ + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?";
+ blobDeleteSQL = "delete from "
+ + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?";
+ }
+ }
- stmts.add(nodeStateInsert =
- con.prepareStatement("insert into "
- + schemaObjectPrefix + "NODE (NODE_DATA, NODE_ID) values (?, ?)"));
- stmts.add(nodeStateUpdate =
- con.prepareStatement("update "
- + schemaObjectPrefix + "NODE set NODE_DATA = ? where NODE_ID = ?"));
- stmts.add(nodeStateSelect =
- con.prepareStatement("select NODE_DATA from "
- + schemaObjectPrefix + "NODE where NODE_ID = ?"));
- stmts.add(nodeStateSelectExist =
- con.prepareStatement("select 1 from "
- + schemaObjectPrefix + "NODE where NODE_ID = ?"));
- stmts.add(nodeStateDelete =
- con.prepareStatement("delete from "
- + schemaObjectPrefix + "NODE where NODE_ID = ?"));
-
- stmts.add(propertyStateInsert =
- con.prepareStatement("insert into "
- + schemaObjectPrefix + "PROP (PROP_DATA, PROP_ID) values (?, ?)"));
- stmts.add(propertyStateUpdate =
- con.prepareStatement("update "
- + schemaObjectPrefix + "PROP set PROP_DATA = ? where PROP_ID = ?"));
- stmts.add(propertyStateSelect =
- con.prepareStatement("select PROP_DATA from "
- + schemaObjectPrefix + "PROP where PROP_ID = ?"));
- stmts.add(propertyStateSelectExist =
- con.prepareStatement("select 1 from "
- + schemaObjectPrefix + "PROP where PROP_ID = ?"));
- stmts.add(propertyStateDelete =
- con.prepareStatement("delete from "
- + schemaObjectPrefix + "PROP where PROP_ID = ?"));
-
- stmts.add(nodeReferenceInsert =
- con.prepareStatement("insert into "
- + schemaObjectPrefix + "REFS (REFS_DATA, NODE_ID) values (?, ?)"));
- stmts.add(nodeReferenceUpdate =
- con.prepareStatement("update "
- + schemaObjectPrefix + "REFS set REFS_DATA = ? where NODE_ID = ?"));
- stmts.add(nodeReferenceSelect =
- con.prepareStatement("select REFS_DATA from "
- + schemaObjectPrefix + "REFS where NODE_ID = ?"));
- stmts.add(nodeReferenceSelectExist =
- con.prepareStatement("select 1 from "
- + schemaObjectPrefix + "REFS where NODE_ID = ?"));
- stmts.add(nodeReferenceDelete =
- con.prepareStatement("delete from "
- + schemaObjectPrefix + "REFS where NODE_ID = ?"));
+ /**
+ * Initializes the map of prepared statements.
+ *
+ * @throws SQLException if an error occurs
+ */
+ protected void initPreparedStatements() throws SQLException {
+ preparedStatements.put(
+ nodeStateInsertSQL, con.prepareStatement(nodeStateInsertSQL));
+ preparedStatements.put(
+ nodeStateUpdateSQL, con.prepareStatement(nodeStateUpdateSQL));
+ preparedStatements.put(
+ nodeStateSelectSQL, con.prepareStatement(nodeStateSelectSQL));
+ preparedStatements.put(
+ nodeStateSelectExistSQL, con.prepareStatement(nodeStateSelectExistSQL));
+ preparedStatements.put(
+ nodeStateDeleteSQL, con.prepareStatement(nodeStateDeleteSQL));
+
+ preparedStatements.put(
+ propertyStateInsertSQL, con.prepareStatement(propertyStateInsertSQL));
+ preparedStatements.put(
+ propertyStateUpdateSQL, con.prepareStatement(propertyStateUpdateSQL));
+ preparedStatements.put(
+ propertyStateSelectSQL, con.prepareStatement(propertyStateSelectSQL));
+ preparedStatements.put(
+ propertyStateSelectExistSQL, con.prepareStatement(propertyStateSelectExistSQL));
+ preparedStatements.put(
+ propertyStateDeleteSQL, con.prepareStatement(propertyStateDeleteSQL));
+
+ preparedStatements.put(
+ nodeReferenceInsertSQL, con.prepareStatement(nodeReferenceInsertSQL));
+ preparedStatements.put(
+ nodeReferenceUpdateSQL, con.prepareStatement(nodeReferenceUpdateSQL));
+ preparedStatements.put(
+ nodeReferenceSelectSQL, con.prepareStatement(nodeReferenceSelectSQL));
+ preparedStatements.put(
+ nodeReferenceSelectExistSQL, con.prepareStatement(nodeReferenceSelectExistSQL));
+ preparedStatements.put(
+ nodeReferenceDeleteSQL, con.prepareStatement(nodeReferenceDeleteSQL));
if (!externalBLOBs) {
- stmts.add(blobInsert =
- con.prepareStatement("insert into "
- + schemaObjectPrefix + "BINVAL (BINVAL_DATA, BINVAL_ID) values (?, ?)"));
- stmts.add(blobUpdate =
- con.prepareStatement("update "
- + schemaObjectPrefix + "BINVAL set BINVAL_DATA = ? where BINVAL_ID = ?"));
- stmts.add(blobSelect =
- con.prepareStatement("select BINVAL_DATA from "
- + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?"));
- stmts.add(blobSelectExist =
- con.prepareStatement("select 1 from "
- + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?"));
- stmts.add(blobDelete =
- con.prepareStatement("delete from "
- + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?"));
+ preparedStatements.put(blobInsertSQL, con.prepareStatement(blobInsertSQL));
+ preparedStatements.put(blobUpdateSQL, con.prepareStatement(blobUpdateSQL));
+ preparedStatements.put(blobSelectSQL, con.prepareStatement(blobSelectSQL));
+ preparedStatements.put(blobSelectExistSQL, con.prepareStatement(blobSelectExistSQL));
+ preparedStatements.put(blobDeleteSQL, con.prepareStatement(blobDeleteSQL));
}
- return stmts;
}
//--------------------------------------------------------< inner classes >
+
+ class SizedInputStream extends FilterInputStream {
+ private final long size;
+ private boolean consumed = false;
+
+ SizedInputStream(InputStream in, long size) {
+ super(in);
+ this.size = size;
+ }
+
+ long getSize() {
+ return size;
+ }
+
+ boolean isConsumed() {
+ return consumed;
+ }
+
+ public int read() throws IOException {
+ consumed = true;
+ return super.read();
+ }
+
+ public long skip(long n) throws IOException {
+ consumed = true;
+ return super.skip(n);
+ }
+
+ public int read(byte b[]) throws IOException {
+ consumed = true;
+ return super.read(b);
+ }
+
+ public int read(byte b[], int off, int len) throws IOException {
+ consumed = true;
+ return super.read(b, off, len);
+ }
+ }
+
class DbBLOBStore implements BLOBStore {
/**
* {@inheritDoc}
@@ -1014,38 +1183,32 @@
* {@inheritDoc}
*/
public InputStream get(String blobId) throws Exception {
- PreparedStatement stmt = blobSelect;
- synchronized (stmt) {
- try {
- stmt.setString(1, blobId);
- stmt.execute();
- final ResultSet rs = stmt.getResultSet();
- if (!rs.next()) {
- closeResultSet(rs);
- throw new Exception("no such BLOB: " + blobId);
- }
- InputStream in = rs.getBinaryStream(1);
- if (in == null) {
- // some databases treat zero-length values as NULL;
- // return empty InputStream in such a case
+ synchronized (blobSelectSQL) {
+ Statement stmt = executeStmt(blobSelectSQL, new Object[]{blobId});
+ final ResultSet rs = stmt.getResultSet();
+ if (!rs.next()) {
+ closeResultSet(rs);
+ throw new Exception("no such BLOB: " + blobId);
+ }
+ InputStream in = rs.getBinaryStream(1);
+ if (in == null) {
+ // some databases treat zero-length values as NULL;
+ // return empty InputStream in such a case
+ closeResultSet(rs);
+ return new ByteArrayInputStream(new byte[0]);
+ }
+
+ /**
+ * return an InputStream wrapper in order to
+ * close the ResultSet when the stream is closed
+ */
+ return new FilterInputStream(in) {
+ public void close() throws IOException {
+ in.close();
+ // now it's safe to close ResultSet
closeResultSet(rs);
- return new ByteArrayInputStream(new byte[0]);
}
-
- /**
- * return an InputStream wrapper in order to
- * close the ResultSet when the stream is closed
- */
- return new FilterInputStream(in) {
- public void close() throws IOException {
- in.close();
- // now it's safe to close ResultSet
- closeResultSet(rs);
- }
- };
- } finally {
- resetStatement(stmt);
- }
+ };
}
}
@@ -1054,36 +1217,22 @@
*/
public synchronized void put(String blobId, InputStream in, long size)
throws Exception {
- PreparedStatement stmt = blobSelectExist;
- try {
- stmt.setString(1, blobId);
- stmt.execute();
- ResultSet rs = stmt.getResultSet();
- // a BLOB exists if the result has at least one entry
- boolean exists = rs.next();
- resetStatement(stmt);
- closeResultSet(rs);
+ Statement stmt = executeStmt(blobSelectExistSQL, new Object[]{blobId});
+ ResultSet rs = stmt.getResultSet();
+ // a BLOB exists if the result has at least one entry
+ boolean exists = rs.next();
+ closeResultSet(rs);
- stmt = (exists) ? blobUpdate : blobInsert;
- stmt.setBinaryStream(1, in, (int) size);
- stmt.setString(2, blobId);
- stmt.executeUpdate();
- } finally {
- resetStatement(stmt);
- }
+ String sql = (exists) ? blobUpdateSQL : blobInsertSQL;
+ executeStmt(sql, new Object[]{new SizedInputStream(in, size), blobId});
}
/**
* {@inheritDoc}
*/
public synchronized boolean remove(String blobId) throws Exception {
- PreparedStatement stmt = blobDelete;
- try {
- stmt.setString(1, blobId);
- return stmt.executeUpdate() == 1;
- } finally {
- resetStatement(stmt);
- }
+ Statement stmt = executeStmt(blobDeleteSQL, new Object[]{blobId});
+ return stmt.getUpdateCount() == 1;
}
}
}
Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java?view=diff&rev=478892&r1=478891&r2=478892
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java Fri Nov 24 06:40:22 2006
@@ -143,7 +143,7 @@
// check if insert or update
boolean update = state.getStatus() != ItemState.STATUS_NEW;
//boolean update = exists((NodeId) state.getId());
- PreparedStatement stmt = (update) ? nodeStateUpdate : nodeStateInsert;
+ String sql = (update) ? nodeStateUpdateSQL : nodeStateInsertSQL;
Blob blob = null;
try {
@@ -153,12 +153,9 @@
Serializer.serialize(state, out);
// we are synchronized on this instance, therefore we do not
- // not have to additionally synchronize on the preparedStatement
-
+ // not have to additionally synchronize on the sql statement
blob = createTemporaryBlob(new ByteArrayInputStream(out.toByteArray()));
- stmt.setBlob(1, blob);
- stmt.setString(2, state.getId().toString());
- stmt.executeUpdate();
+ executeStmt(sql, new Object[]{blob, state.getNodeId().toString()});
// there's no need to close a ByteArrayOutputStream
//out.close();
@@ -167,11 +164,10 @@
log.error(msg, e);
throw new ItemStateException(msg, e);
} finally {
- resetStatement(stmt);
if (blob != null) {
try {
freeTemporaryBlob(blob);
- } catch (Exception e1) {
+ } catch (Exception ignore) {
}
}
}
@@ -188,7 +184,7 @@
// check if insert or update
boolean update = state.getStatus() != ItemState.STATUS_NEW;
//boolean update = exists((PropertyId) state.getId());
- PreparedStatement stmt = (update) ? propertyStateUpdate : propertyStateInsert;
+ String sql = (update) ? propertyStateUpdateSQL : propertyStateInsertSQL;
Blob blob = null;
try {
@@ -198,12 +194,9 @@
Serializer.serialize(state, out, blobStore);
// we are synchronized on this instance, therefore we do not
- // not have to additionally synchronize on the preparedStatement
-
+ // not have to additionally synchronize on the sql statement
blob = createTemporaryBlob(new ByteArrayInputStream(out.toByteArray()));
- stmt.setBlob(1, blob);
- stmt.setString(2, state.getId().toString());
- stmt.executeUpdate();
+ executeStmt(sql, new Object[]{blob, state.getPropertyId().toString()});
// there's no need to close a ByteArrayOutputStream
//out.close();
@@ -212,11 +205,10 @@
log.error(msg, e);
throw new ItemStateException(msg, e);
} finally {
- resetStatement(stmt);
if (blob != null) {
try {
freeTemporaryBlob(blob);
- } catch (Exception e1) {
+ } catch (Exception ignore) {
}
}
}
@@ -232,7 +224,7 @@
// check if insert or update
boolean update = exists(refs.getId());
- PreparedStatement stmt = (update) ? nodeReferenceUpdate : nodeReferenceInsert;
+ String sql = (update) ? nodeReferenceUpdateSQL : nodeReferenceInsertSQL;
Blob blob = null;
try {
@@ -242,12 +234,9 @@
Serializer.serialize(refs, out);
// we are synchronized on this instance, therefore we do not
- // not have to additionally synchronize on the preparedStatement
-
+ // not have to additionally synchronize on the sql statement
blob = createTemporaryBlob(new ByteArrayInputStream(out.toByteArray()));
- stmt.setBlob(1, blob);
- stmt.setString(2, refs.getId().toString());
- stmt.executeUpdate();
+ executeStmt(sql, new Object[]{blob, refs.getId().toString()});
// there's no need to close a ByteArrayOutputStream
//out.close();
@@ -256,11 +245,10 @@
log.error(msg, e);
throw new ItemStateException(msg, e);
} finally {
- resetStatement(stmt);
if (blob != null) {
try {
freeTemporaryBlob(blob);
- } catch (Exception e1) {
+ } catch (Exception ignore) {
}
}
}
@@ -384,29 +372,22 @@
*/
public synchronized void put(String blobId, InputStream in, long size)
throws Exception {
- PreparedStatement stmt = blobSelectExist;
+ Statement stmt = executeStmt(blobSelectExistSQL, new Object[]{blobId});
+ ResultSet rs = stmt.getResultSet();
+ // a BLOB exists if the result has at least one entry
+ boolean exists = rs.next();
+ closeResultSet(rs);
+
Blob blob = null;
try {
- stmt.setString(1, blobId);
- stmt.execute();
- ResultSet rs = stmt.getResultSet();
- // a BLOB exists if the result has at least one entry
- boolean exists = rs.next();
- resetStatement(stmt);
- closeResultSet(rs);
-
- stmt = (exists) ? blobUpdate : blobInsert;
-
+ String sql = (exists) ? blobUpdateSQL : blobInsertSQL;
blob = createTemporaryBlob(in);
- stmt.setBlob(1, blob);
- stmt.setString(2, blobId);
- stmt.executeUpdate();
+ executeStmt(sql, new Object[]{blob, blobId});
} finally {
- resetStatement(stmt);
if (blob != null) {
try {
freeTemporaryBlob(blob);
- } catch (Exception e1) {
+ } catch (Exception ignore) {
}
}
}