All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.search.backend.impl.TransactionalWorker Maven / Gradle / Ivy

There is a newer version: 5.11.12.Final
Show newest version
/*
 * Hibernate Search, full-text search for your domain model
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.search.backend.impl;

import java.util.Properties;
import java.util.concurrent.ConcurrentMap;

import org.hibernate.search.exception.AssertionFailure;
import org.hibernate.search.backend.spi.Work;
import org.hibernate.search.backend.spi.WorkType;
import org.hibernate.search.backend.spi.Worker;
import org.hibernate.search.engine.integration.impl.SearchFactoryImplementor;
import org.hibernate.search.engine.spi.EntityIndexBinding;
import org.hibernate.search.indexes.interceptor.EntityIndexingInterceptor;
import org.hibernate.search.indexes.interceptor.IndexingOverride;
import org.hibernate.search.util.impl.Maps;
import org.hibernate.search.util.logging.impl.Log;
import org.hibernate.search.exception.SearchException;
import org.hibernate.search.backend.TransactionContext;
import org.hibernate.search.spi.InstanceInitializer;
import org.hibernate.search.spi.WorkerBuildContext;
import org.hibernate.search.util.logging.impl.LoggerFactory;

/**
 * Queue works per transaction.
 * If out of transaction, the work is executed right away
 * 

* When hibernate.search.worker.type is set to async * the work is done in a separate thread (threads are pooled) * * @author Emmanuel Bernard */ public class TransactionalWorker implements Worker { //note: there is one Worker instance per SearchFactory, reused concurrently for all sessions. private static final Log log = LoggerFactory.make(); //this is being used from different threads, but doesn't need a //synchronized map since for a given transaction, we have not concurrent access protected final ConcurrentMap synchronizationPerTransaction = Maps.createIdentityWeakKeyConcurrentMap( 64, 32 ); private QueueingProcessor queueingProcessor; private SearchFactoryImplementor factory; private InstanceInitializer instanceInitializer; private boolean transactionExpected; @Override public void performWork(Work work, TransactionContext transactionContext) { final Class entityType = instanceInitializer.getClassFromWork( work ); EntityIndexBinding indexBindingForEntity = factory.getIndexBinding( entityType ); if ( indexBindingForEntity == null && factory.getDocumentBuilderContainedEntity( entityType ) == null ) { throw new SearchException( "Unable to perform work. Entity Class is not @Indexed nor hosts @ContainedIn: " + entityType ); } work = interceptWork( indexBindingForEntity, work ); if ( work == null ) { //nothing to do return; } if ( transactionContext.isTransactionInProgress() ) { final Object transactionIdentifier = transactionContext.getTransactionIdentifier(); PostTransactionWorkQueueSynchronization txSync = synchronizationPerTransaction.get( transactionIdentifier ); if ( txSync == null || txSync.isConsumed() ) { txSync = new PostTransactionWorkQueueSynchronization( transactionIdentifier, queueingProcessor, synchronizationPerTransaction, factory ); transactionContext.registerSynchronization( txSync ); synchronizationPerTransaction.put( transactionIdentifier, txSync ); } txSync.add( work ); } else { if ( transactionExpected ) { // this is a workaround: isTransactionInProgress should return "true" // for correct configurations. log.pushedChangesOutOfTransaction(); } WorkQueue queue = new WorkQueue( factory ); queueingProcessor.add( work, queue ); queueingProcessor.prepareWorks( queue ); queueingProcessor.performWorks( queue ); } } private Work interceptWork(EntityIndexBinding indexBindingForEntity, Work work) { if ( indexBindingForEntity == null ) { return work; } EntityIndexingInterceptor interceptor = indexBindingForEntity.getEntityIndexingInterceptor(); if ( interceptor == null ) { return work; } IndexingOverride operation; switch ( work.getType() ) { case ADD: operation = interceptor.onAdd( work.getEntity() ); break; case UPDATE: operation = interceptor.onUpdate( work.getEntity() ); break; case DELETE: operation = interceptor.onDelete( work.getEntity() ); break; case COLLECTION: operation = interceptor.onCollectionUpdate( work.getEntity() ); break; case PURGE: case PURGE_ALL: case INDEX: operation = IndexingOverride.APPLY_DEFAULT; break; default: throw new AssertionFailure( "Unknown work type: " + work.getType() ); } Work result = work; Class entityClass = work.getEntityClass(); switch ( operation ) { case APPLY_DEFAULT: break; case SKIP: result = null; log.forceSkipIndexOperationViaInterception( entityClass, work.getType() ); break; case UPDATE: result = new Work( work.getEntity(), work.getId(), WorkType.UPDATE ); log.forceUpdateOnIndexOperationViaInterception( entityClass, work.getType() ); break; case REMOVE: //This works because other Work constructors are never used from WorkType ADD, UPDATE, REMOVE, COLLECTION //TODO should we force isIdentifierRollback to false if the operation is not a delete? result = new Work( work.getEntity(), work.getId(), WorkType.DELETE, work.isIdentifierWasRolledBack() ); log.forceRemoveOnIndexOperationViaInterception( entityClass, work.getType() ); break; default: throw new AssertionFailure( "Unknown action type: " + operation ); } return result; } @Override public void initialize(Properties props, WorkerBuildContext context, QueueingProcessor queueingProcessor) { this.queueingProcessor = queueingProcessor; this.factory = context.getUninitializedSearchFactory(); this.transactionExpected = context.isTransactionManagerExpected(); this.instanceInitializer = context.getInstanceInitializer(); } @Override public void close() { } @Override public void flushWorks(TransactionContext transactionContext) { if ( transactionContext.isTransactionInProgress() ) { Object transaction = transactionContext.getTransactionIdentifier(); PostTransactionWorkQueueSynchronization txSync = (PostTransactionWorkQueueSynchronization) synchronizationPerTransaction.get( transaction ); if ( txSync != null && !txSync.isConsumed() ) { txSync.flushWorks(); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy