Skip to content

Commit

Permalink
MODE-1854 - Fixed indexing during user transactions: previously, the …
Browse files Browse the repository at this point in the history
…indexing operations were submitted on a transaction in state COMMITTED, causing Hibernate Search to no see an active transaction.
  • Loading branch information
Horia Chiorean committed Mar 21, 2013
1 parent 88809fa commit 50e3e7e
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 190 deletions.
80 changes: 45 additions & 35 deletions modeshape-jcr/src/main/java/org/modeshape/jcr/JcrRepository.java
Expand Up @@ -1788,46 +1788,21 @@ protected Transaction currentTransaction() {

@Override
public Monitor createMonitor() {
final Transaction txn = currentTransaction();
final RepositoryStatistics statistics = this.runningState.statistics();
final RepositoryNodeTypeManager nodeTypeManager = this.runningState.nodeTypeManager();
final RepositoryQueryManager queryManager = this.runningState.queryManager();
if (nodeTypeManager == null || queryManager == null) {
// Happens only when the repository's initial content is being initialized,
// so return a monitor that captures statistics but does not index ...
return new Monitor() {
@Override
public void recordChanged( long changedNodesCount ) {
// ValueMetric.SESSION_SAVES are tracked in JcrSession.save() ...
statistics.increment(ValueMetric.NODE_CHANGES, changedNodesCount);
}

@Override
public void recordAdd( String workspace,
NodeKey key,
org.modeshape.jcr.value.Path path,
Name primaryType,
Set<Name> mixinTypes,
Collection<Property> properties ) {
}

@Override
public void recordRemove( String workspace,
Iterable<NodeKey> keys ) {
}

@Override
public void recordUpdate( String workspace,
NodeKey key,
org.modeshape.jcr.value.Path path,
Name primaryType,
Set<Name> mixinTypes,
Iterator<Property> properties ) {
}
};
//query isn't enabled most likely, so we'll only record statistics
return statisticsMonitor();
}
return indexingMonitor(nodeTypeManager, queryManager);
}

private Monitor indexingMonitor( RepositoryNodeTypeManager nodeTypeManager,
RepositoryQueryManager queryManager ) {
final NodeTypeSchemata schemata = nodeTypeManager.getRepositorySchemata();
final QueryIndexing indexes = queryManager.getIndexes();
//a transaction will be returned only if it exists and is in ACTIVE status
final Transaction txn = currentTransaction();
final TransactionContext txnCtx = new TransactionContext() {
@Override
public Object getTransactionIdentifier() {
Expand Down Expand Up @@ -1857,7 +1832,7 @@ public void registerSynchronization( Synchronization synchronization ) {
@Override
public void recordChanged( long changedNodesCount ) {
// ValueMetric.SESSION_SAVES are tracked in JcrSession.save() ...
statistics.increment(ValueMetric.NODE_CHANGES, changedNodesCount);
runningState.statistics.increment(ValueMetric.NODE_CHANGES, changedNodesCount);
}

@Override
Expand Down Expand Up @@ -1888,6 +1863,41 @@ public void recordRemove( String workspace,
};
}

private Monitor statisticsMonitor() {
// Happens only when the repository's initial content is being initialized,
// so return a monitor that captures statistics but does not index ...
return new Monitor() {
@Override
public void recordChanged( long changedNodesCount ) {
// ValueMetric.SESSION_SAVES are tracked in JcrSession.save() ...
runningState.statistics.increment(ValueMetric.NODE_CHANGES, changedNodesCount);
}

@Override
public void recordAdd( String workspace,
NodeKey key,
org.modeshape.jcr.value.Path path,
Name primaryType,
Set<Name> mixinTypes,
Collection<Property> properties ) {
}

@Override
public void recordRemove( String workspace,
Iterable<NodeKey> keys ) {
}

@Override
public void recordUpdate( String workspace,
NodeKey key,
org.modeshape.jcr.value.Path path,
Name primaryType,
Set<Name> mixinTypes,
Iterator<Property> properties ) {
}
};
}

}

private final class InternalSecurityContext implements SecurityContext {
Expand Down
Expand Up @@ -26,6 +26,7 @@
import java.io.File;
import java.util.Properties;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.hibernate.search.Environment;
import org.hibernate.search.backend.impl.jgroups.JGroupsChannelProvider;
import org.hibernate.search.cfg.spi.SearchConfiguration;
import org.modeshape.jcr.RepositoryConfiguration;
Expand Down Expand Up @@ -157,11 +158,11 @@ public BasicLuceneConfiguration( String repositoryName,
// Hibernate Search defaults to StandardAnalyzer, which is also our default. But there's an issue loading
// the class when running in AS7, because ConfigContext uses org.hibernate.annotations.common.util.ReflectHelper,
// which apparently uses the Hibernate module's classpath (which does not contain the Lucene library).
setProperty("hibernate.search.analyzer", analyzer);
setProperty(Environment.ANALYZER_CLASS, analyzer);
}
setProperty("hibernate.search.similarity", similarity);
setProperty("hibernate.search.worker.batch_size", batchSize);
setProperty("hibernate.search.lucene_version", indexFormat);
setProperty(Environment.SIMILARITY_CLASS, similarity);
setProperty(Environment.QUEUEINGPROCESSOR_BATCHSIZE, batchSize);
setProperty(Environment.LUCENE_MATCH_VERSION, indexFormat);
setProperty("hibernate.search.reader.strategy", readerStrategy);
setProperty("hibernate.search.default.worker.execution", mode); // sync or async
setProperty("hibernate.search.default.worker.thread_pool.size", asyncThreadPoolSize);
Expand Down
Expand Up @@ -23,26 +23,19 @@
*/
package org.modeshape.jcr.txn;

import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import org.modeshape.jcr.cache.NodeKey;
import org.modeshape.jcr.cache.SessionEnvironment.Monitor;
import org.modeshape.jcr.cache.SessionEnvironment.MonitorFactory;
import org.modeshape.jcr.cache.change.ChangeSet;
import org.modeshape.jcr.cache.document.TransactionalWorkspaceCache;
import org.modeshape.jcr.cache.document.WorkspaceCache;
import org.modeshape.jcr.value.Name;
import org.modeshape.jcr.value.Path;
import org.modeshape.jcr.value.Property;

/**
* An implementation of {@link Transactions} that will attempt to register a {@link Synchronization} with the current transaction.
Expand Down Expand Up @@ -106,7 +99,6 @@ public void updateCache( WorkspaceCache workspace,
protected class SynchronizedTransaction extends BaseTransaction {

private final Synchronization synchronization;
private final AccumulatingMonitor monitor;
private final List<WorkspaceUpdates> updates = new LinkedList<WorkspaceUpdates>();
private boolean finished = false;

Expand Down Expand Up @@ -135,7 +127,6 @@ public void afterCompletion( int status ) {
}
};
txnMgr.getTransaction().registerSynchronization(synchronization);
this.monitor = new AccumulatingMonitor();
}

protected void addUpdate( WorkspaceUpdates updates ) {
Expand All @@ -144,11 +135,6 @@ protected void addUpdate( WorkspaceUpdates updates ) {
this.updates.add(updates);
}

@Override
public Monitor createMonitor() {
return this.monitor;
}

@Override
public void commit() {
// This transaction spans more than just our usage, so we don't commit anything here ...
Expand All @@ -167,9 +153,6 @@ protected void afterCommit() {
// Execute the functions
executeFunctions();

// Forward the accumulated monitoring calls (e.g., indexing updates) ...
monitor.forward(newMonitor());

// Apply the updates, and do AFTER the monitor is updated ...
for (WorkspaceUpdates update : updates) {
update.apply();
Expand Down Expand Up @@ -218,138 +201,4 @@ protected void apply() {
workspace.changed(changes);
}
}

protected static final class AccumulatingMonitor implements Monitor {
private final List<Call> calls = new LinkedList<Call>();

protected AccumulatingMonitor() {
}

@Override
public void recordAdd( String workspace,
NodeKey key,
Path path,
Name primaryType,
Set<Name> mixinTypes,
Collection<Property> properties ) {
calls.add(new AddCall(workspace, key, path, primaryType, mixinTypes, properties));
}

@Override
public void recordChanged( long changedNodesCount ) {
calls.add(new ChangedCall(changedNodesCount));
}

@Override
public void recordRemove( String workspace,
Iterable<NodeKey> keys ) {
calls.add(new RemoveCall(workspace, keys));
}

@Override
public void recordUpdate( String workspace,
NodeKey key,
Path path,
Name primaryType,
Set<Name> mixinTypes,
Iterator<Property> properties ) {
calls.add(new UpdateCall(workspace, key, path, primaryType, mixinTypes, properties));
}

protected void forward( Monitor delegate ) {
for (Call call : calls) {
call.send(delegate);
}
calls.clear();
}
}

protected static interface Call {
void send( Monitor monitor );
}

protected static final class AddCall implements Call {
private final String workspace;
private final NodeKey key;
private final Path path;
private final Name primaryType;
private final Set<Name> mixinTypes;
private final Collection<Property> properties;

protected AddCall( String workspace,
NodeKey key,
Path path,
Name primaryType,
Set<Name> mixinTypes,
Collection<Property> properties ) {
this.workspace = workspace;
this.key = key;
this.path = path;
this.primaryType = primaryType;
this.mixinTypes = mixinTypes;
this.properties = properties;
}

@Override
public void send( Monitor monitor ) {
monitor.recordAdd(workspace, key, path, primaryType, mixinTypes, properties);
}
}

protected static final class UpdateCall implements Call {
private final String workspace;
private final NodeKey key;
private final Path path;
private final Name primaryType;
private final Set<Name> mixinTypes;
private final Iterator<Property> properties;

protected UpdateCall( String workspace,
NodeKey key,
Path path,
Name primaryType,
Set<Name> mixinTypes,
Iterator<Property> properties ) {
this.workspace = workspace;
this.key = key;
this.path = path;
this.primaryType = primaryType;
this.mixinTypes = mixinTypes;
this.properties = properties;
}

@Override
public void send( Monitor monitor ) {
monitor.recordUpdate(workspace, key, path, primaryType, mixinTypes, properties);
}
}

protected static final class RemoveCall implements Call {
private final String workspace;
private final Iterable<NodeKey> keys;

protected RemoveCall( String workspace,
Iterable<NodeKey> keys ) {
this.workspace = workspace;
this.keys = keys;
}

@Override
public void send( Monitor monitor ) {
monitor.recordRemove(workspace, keys);
}
}

protected static final class ChangedCall implements Call {
private final long count;

protected ChangedCall( long count ) {
this.count = count;
}

@Override
public void send( Monitor monitor ) {
monitor.recordChanged(count);
}
}
}

0 comments on commit 50e3e7e

Please sign in to comment.