Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java (revision 618196) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/cluster/ClusterNode.java (working copy) @@ -26,7 +26,7 @@ import org.apache.jackrabbit.core.journal.RecordConsumer; import org.apache.jackrabbit.core.journal.Record; import org.apache.jackrabbit.core.journal.JournalException; -import org.apache.jackrabbit.core.journal.FileRevision; +import org.apache.jackrabbit.core.journal.InstanceRevision; import org.apache.jackrabbit.core.nodetype.InvalidNodeTypeDefException; import org.apache.jackrabbit.core.nodetype.NodeTypeDef; import org.apache.jackrabbit.core.observation.EventState; @@ -50,7 +50,6 @@ import java.util.Iterator; import java.util.Set; import java.util.HashSet; -import java.io.File; /** * Default clustered node implementation. @@ -64,11 +63,6 @@ public static final String SYSTEM_PROPERTY_NODE_ID = "org.apache.jackrabbit.core.cluster.node_id"; /** - * Revision counter parameter name. - */ - private static final String REVISION_NAME = "revision"; - - /** * Used for padding short string representations. */ private static final String SHORT_PADDING = "0000"; @@ -174,9 +168,9 @@ private NodeTypeEventListener nodeTypeListener; /** - * Instance revision file. + * Instance revision manager. */ - private FileRevision instanceRevision; + private InstanceRevision instanceRevision; /** * Workspace name used when consuming records. @@ -219,18 +213,11 @@ clusterNodeId = getClusterNodeId(cc.getId()); syncDelay = cc.getSyncDelay(); - JournalConfig jc = cc.getJournalConfig(); - - String revisionName = jc.getParameters().getProperty(REVISION_NAME); - if (revisionName == null) { - String msg = "Revision not specified."; - throw new ClusterException(msg); - } try { - instanceRevision = new FileRevision(new File(revisionName)); - + JournalConfig jc = cc.getJournalConfig(); journal = (Journal) jc.newInstance(); journal.init(clusterNodeId, clusterContext.getNamespaceResovler()); + instanceRevision = journal.getInstanceRevision(); journal.register(this); } catch (ConfigurationException e) { throw new ClusterException(e.getMessage(), e.getCause()); Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java (revision 618196) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/AbstractJournal.java (working copy) @@ -71,6 +71,15 @@ private final ReadWriteLock rwLock = new ReentrantWriterPreferenceReadWriteLock(); /** + * The path of the local revision file on disk. Configurable through the repository.xml. + * + * Note: this field is not located in the FileJournal class for upgrade reasons (before + * JCR-1087 had been fixed all Journals used a revision file on the local file system. + * Also see {@link DatabaseJournal#initInstanceRevisionAndJanitor()}). + */ + private String revision; + + /** * {@inheritDoc} */ public void init(String id, NamespaceResolver resolver) throws JournalException { @@ -336,5 +345,22 @@ public NamePathResolver getNamePathResolver() { return npResolver; } + + /* + * Bean getters and setters. + */ + + /** + * @return the path of the cluster node's local revision file + */ + public String getRevision() { + return revision; + } + /** + * @param revision the path of the cluster node's local revision file to set + */ + public void setRevision(String revision) { + this.revision = revision; + } } Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java =================================================================== --- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java (revision 618196) +++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/DatabaseJournal.java (working copy) @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -32,6 +33,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.Calendar; import javax.jcr.RepositoryException; @@ -43,8 +45,6 @@ *
* It is configured through the following properties: *revision: the filename where the parent cluster node's revision
- * file should be written to; this is a required property with no default valuedriver: the JDBC driver class name to use; this is a required
* property with no default valueurl: the JDBC connection url; this is a required property with
@@ -56,7 +56,14 @@
* user: username to specify when connectingpassword: password to specify when connectingreconnectDelayMs: number of milliseconds to wait before
- * trying to reconnect to the database.
+ * trying to reconnect to the database.janitorEnabled: specifies whether the clean-up thread for the
+ * journal table is enabled (default = false)janitorSleep: specifies the sleep time of the clean-up thread
+ * in seconds (only useful when the clean-up thread is enabled, default = 24 * 60 * 60,
+ * which equals 24 hours)janitorFirstRunHourOfDay: specifies the hour at which the clean-up
+ * thread initiates its first run (default = 3 which means 3:00 at night)
* JNDI can be used to get the connection. In this case, use the javax.naming.InitialContext as the driver,
* and the JNDI name as the URL. If the user and password are configured in the JNDI resource,
@@ -86,6 +93,11 @@
private static final String DEFAULT_JOURNAL_TABLE = "JOURNAL";
/**
+ * Local revisions table name, used to check schema completeness.
+ */
+ private static final String LOCAL_REVISIONS_TABLE = "LOCAL_REVISIONS";
+
+ /**
* Default reconnect delay in milliseconds.
*/
private static final long DEFAULT_RECONNECT_DELAY_MS = 10000;
@@ -151,6 +163,31 @@
private PreparedStatement insertRevisionStmt;
/**
+ * Statement returning the minimum of the local revisions.
+ */
+ private PreparedStatement selectMinLocalRevisionStmt;
+
+ /**
+ * Statement removing a set of revisions with from the journal table.
+ */
+ private PreparedStatement cleanRevisionStmt;
+
+ /**
+ * Statement returning the local revision of this cluster node.
+ */
+ private PreparedStatement getLocalRevisionStmt;
+
+ /**
+ * Statement for inserting the local revision of this cluster node.
+ */
+ private PreparedStatement insertLocalRevisionStmt;
+
+ /**
+ * Statement for updating the local revision of this cluster node.
+ */
+ private PreparedStatement updateLocalRevisionStmt;
+
+ /**
* Auto commit level.
*/
private int lockLevel;
@@ -166,6 +203,35 @@
private long reconnectTimeMs;
/**
+ * Whether the revision table janitor thread is enabled.
+ */
+ private boolean janitorEnabled = false;
+
+ /**
+ * The sleep time of the revision table janitor in seconds, 1 day default.
+ */
+ private int janitorSleep = 60 * 60 * 24;
+
+ /**
+ * Indicates when the next run of the janitor is scheduled.
+ * The first run is scheduled by default at 03:00 hours.
+ */
+ private Calendar janitorNextRun = Calendar.getInstance();
+ {
+ if (janitorNextRun.get(Calendar.HOUR_OF_DAY) >= 3) {
+ janitorNextRun.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ janitorNextRun.set(Calendar.HOUR_OF_DAY, 3);
+ janitorNextRun.set(Calendar.MINUTE, 0);
+ janitorNextRun.set(Calendar.SECOND, 0);
+ janitorNextRun.set(Calendar.MILLISECOND, 0);
+ }
+
+ /**
+ * The instance that manages the local revision.
+ */
+ private DatabaseRevision databaseRevision;
+ /**
* SQL statement returning all revisions within a range.
*/
protected String selectRevisionsStmtSQL;
@@ -186,6 +252,31 @@
protected String insertRevisionStmtSQL;
/**
+ * SQL statement returning the minimum of the local revisions.
+ */
+ protected String selectMinLocalRevisionStmtSQL;
+
+ /**
+ * SQL statement removing a set of revisions with from the journal table.
+ */
+ protected String cleanRevisionStmtSQL;
+
+ /**
+ * SQL statement returning the local revision of this cluster node.
+ */
+ protected String getLocalRevisionStmtSQL;
+
+ /**
+ * SQL statement for inserting the local revision of this cluster node.
+ */
+ protected String insertLocalRevisionStmtSQL;
+
+ /**
+ * SQL statement for updating the local revision of this cluster node.
+ */
+ protected String updateLocalRevisionStmtSQL;
+
+ /**
* Schema object prefix, bean property.
*/
protected String schemaObjectPrefix;
@@ -214,6 +305,7 @@
checkSchema();
buildSQLStatements();
prepareStatements();
+ initInstanceRevisionAndJanitor();
} catch (Exception e) {
String msg = "Unable to create connection.";
throw new JournalException(msg, e);
@@ -259,6 +351,48 @@
}
/**
+ * Initialize the instance revision manager and the janitor thread.
+ *
+ * @throws JournalException on error
+ */
+ protected void initInstanceRevisionAndJanitor() throws Exception {
+ databaseRevision = new DatabaseRevision();
+
+ // Make sure that the LOCAL_REVISIONS table exists (checkSchema has already been called) (see JCR-1087)
+ checkLocalRevisionSchema();
+
+ // Get the local file revision from disk (upgrade; see JCR-1087)
+ long localFileRevision = 0L;
+ if (getRevision() != null) {
+ InstanceRevision currentFileRevision = new FileRevision(new File(getRevision()));
+ localFileRevision = currentFileRevision.get();
+ currentFileRevision.close();
+ }
+
+ // Now write the localFileRevision (or 0 if it does not exist) to the LOCAL_REVISIONS
+ // table, but only if the LOCAL_REVISIONS table has no entry yet for this cluster node
+ long localRevision = databaseRevision.init(localFileRevision);
+ log.info("Initialized local revision to " + localRevision);
+
+ // Start the clean-up thread if necessary.
+ if (janitorEnabled) {
+ Thread t1 = new Thread(new RevisionTableJanitor(), "ClusterRevisionJanitor");
+ t1.setDaemon(true);
+ t1.start();
+ log.info("Cluster revision janitor thread started; first run scheduled at " + janitorNextRun.getTime());
+ } else {
+ log.info("Cluster revision janitor thread not started");
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.jackrabbit.core.journal.Journal#getInstanceRevision()
+ */
+ public InstanceRevision getInstanceRevision() throws JournalException {
+ return databaseRevision;
+ }
+
+ /**
* Creates a new database connection. This method is called inside
* {@link #init(String, org.apache.jackrabbit.name.NamespaceResolver)} or
* when a connection has been dropped and must be reacquired. Base
@@ -452,7 +586,17 @@
selectGlobalStmt = null;
close(insertRevisionStmt);
insertRevisionStmt = null;
-
+ close(selectMinLocalRevisionStmt);
+ selectMinLocalRevisionStmt = null;
+ close(cleanRevisionStmt);
+ cleanRevisionStmt = null;
+ close(getLocalRevisionStmt);
+ getLocalRevisionStmt = null;
+ close(insertLocalRevisionStmt);
+ insertLocalRevisionStmt = null;
+ close(updateLocalRevisionStmt);
+ updateLocalRevisionStmt = null;
+
close(connection);
connection = null;
}
@@ -607,8 +751,7 @@
* @throws Exception if an error occurs
*/
private void checkSchema() throws Exception {
- if (!schemaExists(connection.getMetaData())) {
- // read ddl from resources
+ if (!tableExists(connection.getMetaData(), schemaObjectPrefix + DEFAULT_JOURNAL_TABLE)) { // read ddl from resources
InputStream in = DatabaseJournal.class.getResourceAsStream(schema + ".ddl");
if (in == null) {
String msg = "No schema-specific DDL found: '" + schema + ".ddl"
@@ -643,6 +786,51 @@
}
/**
+ * Checks if the local revision schema objects exist and creates them if they
+ * don't exist yet.
+ *
+ * @throws Exception if an error occurs
+ */
+ private void checkLocalRevisionSchema() throws Exception {
+ if (!tableExists(connection.getMetaData(), schemaObjectPrefix + LOCAL_REVISIONS_TABLE)) {
+ log.info("Creating " + schemaObjectPrefix + LOCAL_REVISIONS_TABLE + " table");
+ // read ddl from resources
+ InputStream in = DatabaseJournal.class.getResourceAsStream(schema + ".ddl");
+ if (in == null) {
+ String msg = "No schema-specific DDL found: '" + schema + ".ddl" +
+ "', falling back to '" + DEFAULT_DDL_NAME + "'.";
+ log.info(msg);
+ in = DatabaseJournal.class.getResourceAsStream(DEFAULT_DDL_NAME);
+ if (in == null) {
+ msg = "Unable to load '" + DEFAULT_DDL_NAME + "'.";
+ throw new JournalException(msg);
+ }
+ }
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ Statement stmt = connection.createStatement();
+ try {
+ String sql = reader.readLine();
+ while (sql != null) {
+ // Skip comments and empty lines, and select only the statement
+ // to create the LOCAL_REVISIONS table.
+ if (!sql.startsWith("#") && sql.length() > 0
+ && sql.contains(LOCAL_REVISIONS_TABLE)) {
+ // replace prefix variable
+ sql = createSchemaSQL(sql);
+ // execute sql stmt
+ stmt.executeUpdate(sql);
+ }
+ // read next sql stmt
+ sql = reader.readLine();
+ }
+ } finally {
+ close(in);
+ close(stmt);
+ }
+ }
+ }
+
+ /**
* Checks whether the required table(s) exist in the schema. May be
* overridden by subclasses to allow different table names.
*
@@ -650,10 +838,9 @@
* @return true if the schema exists
* @throws SQLException if an SQL error occurs
*/
- protected boolean schemaExists(DatabaseMetaData metaData)
- throws SQLException {
+ protected boolean tableExists(DatabaseMetaData metaData, String tableName)
+ throws SQLException {
- String tableName = schemaObjectPrefix + DEFAULT_JOURNAL_TABLE;
if (metaData.storesLowerCaseIdentifiers()) {
tableName = tableName.toLowerCase();
} else if (metaData.storesUpperCaseIdentifiers()) {
@@ -697,6 +884,19 @@
"insert into " + schemaObjectPrefix + "JOURNAL"
+ " (REVISION_ID, JOURNAL_ID, PRODUCER_ID, REVISION_DATA) "
+ "values (?,?,?,?)";
+ selectMinLocalRevisionStmtSQL =
+ "select MIN(REVISION_ID) from " + schemaObjectPrefix + "LOCAL_REVISIONS";
+ cleanRevisionStmtSQL =
+ "delete from " + schemaObjectPrefix + "JOURNAL " + "where REVISION_ID < ?";
+ getLocalRevisionStmtSQL =
+ "select REVISION_ID from " + schemaObjectPrefix + "LOCAL_REVISIONS "
+ + "where JOURNAL_ID = ?";
+ insertLocalRevisionStmtSQL =
+ "insert into " + schemaObjectPrefix + "LOCAL_REVISIONS "
+ + "(REVISION_ID, JOURNAL_ID) values (?,?)";
+ updateLocalRevisionStmtSQL =
+ "update " + schemaObjectPrefix + "LOCAL_REVISIONS "
+ + "set REVISION_ID = ? where JOURNAL_ID = ?";
}
/**
@@ -709,6 +909,11 @@
updateGlobalStmt = connection.prepareStatement(updateGlobalStmtSQL);
selectGlobalStmt = connection.prepareStatement(selectGlobalStmtSQL);
insertRevisionStmt = connection.prepareStatement(insertRevisionStmtSQL);
+ selectMinLocalRevisionStmt = connection.prepareStatement(selectMinLocalRevisionStmtSQL);
+ cleanRevisionStmt = connection.prepareStatement(cleanRevisionStmtSQL);
+ getLocalRevisionStmt = connection.prepareStatement(getLocalRevisionStmtSQL);
+ insertLocalRevisionStmt = connection.prepareStatement(insertLocalRevisionStmtSQL);
+ updateLocalRevisionStmt = connection.prepareStatement(updateLocalRevisionStmtSQL);
}
/**
@@ -742,6 +947,18 @@
return reconnectDelayMs;
}
+ public boolean getJanitorEnabled() {
+ return janitorEnabled;
+ }
+
+ public int getJanitorSleep() {
+ return janitorSleep;
+ }
+
+ public int getJanitorFirstRunHourOfDay() {
+ return janitorNextRun.get(Calendar.HOUR_OF_DAY);
+ }
+
/**
* Bean setters
*/
@@ -772,4 +989,193 @@
public void setReconnectDelayMs(long reconnectDelayMs) {
this.reconnectDelayMs = reconnectDelayMs;
}
+
+ public void setJanitorEnabled(boolean enabled) {
+ this.janitorEnabled = enabled;
+ }
+
+ public void setJanitorSleep(int sleep) {
+ this.janitorSleep = sleep;
+ }
+
+ public void setJanitorFirstRunHourOfDay(int hourOfDay) {
+ janitorNextRun = Calendar.getInstance();
+ if (janitorNextRun.get(Calendar.HOUR_OF_DAY) >= hourOfDay) {
+ janitorNextRun.add(Calendar.DAY_OF_MONTH, 1);
+ }
+ janitorNextRun.set(Calendar.HOUR_OF_DAY, hourOfDay);
+ janitorNextRun.set(Calendar.MINUTE, 0);
+ janitorNextRun.set(Calendar.SECOND, 0);
+ janitorNextRun.set(Calendar.MILLISECOND, 0);
+ }
+
+ /**
+ * This class manages the local revision of the cluster node. It
+ * persists the local revision in the LOCAL_REVISIONS table in the
+ * clustering database.
+ */
+ public class DatabaseRevision implements InstanceRevision {
+
+ /**
+ * The cached local revision of this cluster node.
+ */
+ private long localRevision;
+
+ /**
+ * Indicates whether the init method has been called.
+ */
+ private boolean initialized = false;
+
+ /**
+ * Checks whether there's a local revision value in the database for this
+ * cluster node. If not, it writes the given default revision to the database.
+ *
+ * @param revision the default value for the local revision counter
+ * @return the local revision
+ * @throws JournalException on error
+ */
+ protected synchronized long init(long revision) throws JournalException {
+ try {
+ // Check whether the connection is available
+ checkConnection();
+
+ // Check whether there is an entry in the database.
+ getLocalRevisionStmt.clearParameters();
+ getLocalRevisionStmt.clearWarnings();
+ getLocalRevisionStmt.setString(1, getId());
+ getLocalRevisionStmt.execute();
+ ResultSet rs = getLocalRevisionStmt.getResultSet();
+ boolean exists = rs.next();
+ if (exists) {
+ revision = rs.getLong(1);
+ }
+ rs.close();
+
+ // Insert the given revision in the database
+ if (!exists) {
+ insertLocalRevisionStmt.clearParameters();
+ insertLocalRevisionStmt.clearWarnings();
+ insertLocalRevisionStmt.setLong(1, revision);
+ insertLocalRevisionStmt.setString(2, getId());
+ insertLocalRevisionStmt.execute();
+ }
+
+ // Set the cached local revision and return
+ localRevision = revision;
+ initialized = true;
+ return revision;
+
+ } catch (SQLException e) {
+ log.warn("Failed to initialize local revision.", e);
+ DatabaseJournal.this.close(true);
+ throw new JournalException("Failed to initialize local revision", e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized long get() {
+ if (!initialized) {
+ throw new IllegalStateException("instance has not yet been initialized");
+ }
+ return localRevision;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized void set(long localRevision) throws JournalException {
+
+ if (!initialized) {
+ throw new IllegalStateException("instance has not yet been initialized");
+ }
+
+ // Update the cached value and the table with local revisions.
+ try {
+ // Check whether the connection is available
+ checkConnection();
+ updateLocalRevisionStmt.clearParameters();
+ updateLocalRevisionStmt.clearWarnings();
+ updateLocalRevisionStmt.setLong(1, localRevision);
+ updateLocalRevisionStmt.setString(2, getId());
+ updateLocalRevisionStmt.execute();
+ this.localRevision = localRevision;
+ } catch (SQLException e) {
+ log.warn("Failed to update local revision.", e);
+ DatabaseJournal.this.close(true);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized void close() {
+ // Do nothing: The statements are closed in DatabaseJournal.close()
+ }
+ }
+
+ /**
+ * Class for maintaining the revision table. This is only useful if all
+ * JR information except the search index is in the database (i.e., node types
+ * etc). In that case, revision data can safely be thrown away from the JOURNAL table.
+ */
+ public class RevisionTableJanitor implements Runnable {
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run() {
+ while (!Thread.currentThread().isInterrupted()) {
+ try {
+ log.info("Next clean-up run scheduled at " + janitorNextRun.getTime());
+ long sleepTime = janitorNextRun.getTimeInMillis() - System.currentTimeMillis();
+ if (sleepTime > 0) {
+ Thread.sleep(sleepTime);
+ }
+ cleanUpOldRevisions();
+ janitorNextRun.add(Calendar.SECOND, janitorSleep);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ log.info("Interrupted: stopping clean-up task.");
+ }
+
+ /**
+ * Cleans old revisions from the clustering table.
+ */
+ protected void cleanUpOldRevisions() {
+ try {
+ long minRevision = 0;
+
+ // Check whether the connection is available
+ checkConnection();
+
+ // Find the minimal local revision
+ selectMinLocalRevisionStmt.clearParameters();
+ selectMinLocalRevisionStmt.clearWarnings();
+ selectMinLocalRevisionStmt.execute();
+ ResultSet rs = selectMinLocalRevisionStmt.getResultSet();
+ boolean cleanUp = rs.next();
+ if (cleanUp) {
+ minRevision = rs.getLong(1);
+ }
+ rs.close();
+
+ // Clean up if necessary:
+ if (cleanUp) {
+ cleanRevisionStmt.clearParameters();
+ cleanRevisionStmt.clearWarnings();
+ cleanRevisionStmt.setLong(1, minRevision);
+ cleanRevisionStmt.execute();
+ log.info("Cleaned old revisions up to revision " + minRevision + ".");
+ }
+
+ } catch (Exception e) {
+ log.warn("Failed to clean up old revisions.", e);
+ close(true);
+ }
+ }
+ }
}
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileJournal.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileJournal.java (revision 618196)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileJournal.java (working copy)
@@ -32,6 +32,8 @@
* file.
revision: the filename where the parent cluster node's revision
+ * file should be written to; this is a required property with no default valuedirectory: the directory where to keep the journal file as
* well as the rotated files; this is a required property with no default valuebasename: the basename of journal files; the default
@@ -103,6 +105,10 @@
public void init(String id, NamespaceResolver resolver) throws JournalException {
super.init(id, resolver);
+ if (getRevision() == null) {
+ String msg = "Revision not specified.";
+ throw new JournalException(msg);
+ }
if (directory == null) {
String msg = "Directory not specified.";
throw new JournalException(msg);
@@ -133,7 +139,7 @@
/**
* {@inheritDoc}
*/
- protected long getRevision() throws JournalException {
+ protected long getGlobalRevision() throws JournalException {
return globalRevision.get();
}
@@ -143,7 +149,7 @@
protected RecordIterator getRecords(long startRevision)
throws JournalException {
- long stopRevision = getRevision();
+ long stopRevision = getGlobalRevision();
File[] logFiles = null;
if (startRevision < stopRevision) {
@@ -210,6 +216,13 @@
}
/**
+ * {@inheritDoc}
+ */
+ public InstanceRevision getInstanceRevision() throws JournalException {
+ return new FileRevision(new File(getRevision()));
+ }
+
+ /**
* Bean getters
*/
public String getDirectory() {
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRevision.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRevision.java (revision 618196)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/FileRevision.java (working copy)
@@ -26,7 +26,7 @@
/**
* Maintains a file-based revision counter with locking, assuring uniqueness.
*/
-public class FileRevision {
+public class FileRevision implements InstanceRevision {
/**
* Logger.
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/InstanceRevision.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/InstanceRevision.java (revision 0)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/InstanceRevision.java (revision 0)
@@ -0,0 +1,44 @@
+/*
+ * 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.jackrabbit.core.journal;
+
+/**
+ *
+ */
+public interface InstanceRevision {
+
+ /**
+ * Return current instance revision.
+ *
+ * @return instance revision
+ * @throws JournalException if some error occurs
+ */
+ public long get() throws JournalException;
+
+ /**
+ * Set current instance revision.
+ *
+ * @param value new instance revision
+ * @throws JournalException if some error occurs
+ */
+ public void set(long value) throws JournalException;
+
+ /**
+ * Closes the instance revision.
+ */
+ public void close();
+}
Property changes on: jackrabbit-core\src\main\java\org\apache\jackrabbit\core\journal\InstanceRevision.java
___________________________________________________________________
Name: svn:keywords
+ LastChangedBy LastChangedDate LastChangedRevision HeadURL
Name: svn:eol-style
+ native
Index: jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/Journal.java
===================================================================
--- jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/Journal.java (revision 618196)
+++ jackrabbit-core/src/main/java/org/apache/jackrabbit/core/journal/Journal.java (working copy)
@@ -72,4 +72,11 @@
*/
void close();
+ /**
+ * Gets the instance that manages the cluster node's local revision.
+ *
+ * @return the InstanceRevision manager
+ * @throws JournalException on error
+ */
+ public InstanceRevision getInstanceRevision() throws JournalException;
}
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/default.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/default.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/default.ddl (working copy)
@@ -16,6 +16,7 @@
create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL)
create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID BIGINT NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/derby.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/derby.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/derby.ddl (working copy)
@@ -16,6 +16,7 @@
create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL)
create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID BIGINT NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/h2.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/h2.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/h2.ddl (working copy)
@@ -18,6 +18,7 @@
set max_length_inplace_lob 4096
create table ${schemaObjectPrefix}JOURNAL (REVISION_ID bigint primary key, JOURNAL_ID varchar(255), PRODUCER_ID varchar(255), REVISION_DATA blob)
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID bigint primary key)
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID bigint NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/mssql.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/mssql.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/mssql.ddl (working copy)
@@ -17,6 +17,7 @@
create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID) ${tableSpace}
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL) ${tableSpace}
create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID) ${tableSpace}
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID BIGINT NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/mysql.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/mysql.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/mysql.ddl (working copy)
@@ -16,6 +16,7 @@
create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL)
create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID BIGINT NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/oracle.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/oracle.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/oracle.ddl (working copy)
@@ -16,6 +16,7 @@
create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID) ${tableSpace}
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID number(20,0) NOT NULL) ${tableSpace}
create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID) ${tableSpace}
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID number(20,0) NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)
Index: jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/postgresql.ddl
===================================================================
--- jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/postgresql.ddl (revision 618196)
+++ jackrabbit-core/src/main/resources/org/apache/jackrabbit/core/journal/postgresql.ddl (working copy)
@@ -16,6 +16,7 @@
create unique index ${schemaObjectPrefix}JOURNAL_IDX on ${schemaObjectPrefix}JOURNAL (REVISION_ID)
create table ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID BIGINT NOT NULL)
create unique index ${schemaObjectPrefix}GLOBAL_REVISION_IDX on ${schemaObjectPrefix}GLOBAL_REVISION (REVISION_ID)
+create table ${schemaObjectPrefix}LOCAL_REVISIONS (JOURNAL_ID varchar(255) NOT NULL, REVISION_ID BIGINT NOT NULL)
# Inserting the one and only revision counter record now helps avoiding race conditions
insert into ${schemaObjectPrefix}GLOBAL_REVISION VALUES(0)