@Override public void close() { if (stopped.compareAndSet(false, true)) { // make sure we only stop once try { worker.close(); } catch (Exception e) { log.workerException(e); } this.allIndexesManager.stop(); this.timingSource.stop(); serviceManager.releaseAllServices(); for (Analyzer an : this.analyzers.values()) { an.close(); } for (AbstractDocumentBuilder documentBuilder : this.documentBuildersContainedEntities.values()) { documentBuilder.close(); } for (EntityIndexBinding entityIndexBinding : this.indexBindingForEntities.values()) { entityIndexBinding.getDocumentBuilder().close(); } // unregister statistic mbean if (statisticsMBeanName != null) { JMXRegistrar.unRegisterMBean(statisticsMBeanName); } } }
@Override public void optimize(Class entityType) { EntityIndexBinding entityIndexBinding = getSafeIndexBindingForEntity(entityType); for (IndexManager im : entityIndexBinding.getIndexManagers()) { im.optimize(); } }
@Test public void testInitialiseDynamicShardsOnStartup() throws Exception { EntityIndexBinding entityIndexBinding = getExtendedSearchIntegrator().getIndexBindings().get(Animal.class); assertThat(entityIndexBinding.getIndexManagers()).hasSize(0); insertAnimals(elephant, spider, bear); assertThat(entityIndexBinding.getIndexManagers()).hasSize(2); assertThat(getIndexManagersAfterReopening()).hasSize(2); }
@SuppressWarnings("unchecked") private void index( Object entity, Session session, InstanceInitializer sessionInitializer, ConversionContext conversionContext) throws InterruptedException { // abort if the thread has been interrupted while not in wait(), I/O or similar which themselves // would have // raised the InterruptedException if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } Serializable id = session.getIdentifier(entity); Class<?> clazz = HibernateHelper.getClass(entity); EntityIndexBinding entityIndexBinding = entityIndexBindings.get(clazz); if (entityIndexBinding == null) { // it might be possible to receive not-indexes subclasses of the currently indexed type; // being not-indexed, we skip them. // FIXME for improved performance: avoid loading them in an early phase. return; } EntityIndexingInterceptor interceptor = entityIndexBinding.getEntityIndexingInterceptor(); if (interceptor != null) { IndexingOverride onAdd = interceptor.onAdd(entity); switch (onAdd) { case REMOVE: case SKIP: return; } // default: continue indexing this instance } DocumentBuilderIndexedEntity docBuilder = entityIndexBinding.getDocumentBuilder(); TwoWayFieldBridge idBridge = docBuilder.getIdBridge(); conversionContext.pushProperty(docBuilder.getIdKeywordName()); String idInString = null; try { idInString = conversionContext.setClass(clazz).twoWayConversionContext(idBridge).objectToString(id); } finally { conversionContext.popProperty(); } // depending on the complexity of the object graph going to be indexed it's possible // that we hit the database several times during work construction. AddLuceneWork addWork = docBuilder.createAddWork( tenantId, clazz, entity, id, idInString, sessionInitializer, conversionContext); backend.enqueueAsyncWork(addWork); }
private Collection<IndexManager> uniqueIndexManagerForTypes(Collection<Class<?>> entityTypes) { HashMap<String, IndexManager> uniqueBackends = new HashMap<String, IndexManager>(entityTypes.size()); for (Class<?> type : entityTypes) { EntityIndexBinding indexBindingForEntity = searchFactoryImplementor.getIndexBinding(type); if (indexBindingForEntity != null) { IndexManager[] indexManagers = indexBindingForEntity.getIndexManagers(); for (IndexManager im : indexManagers) { uniqueBackends.put(im.getIndexName(), im); } } } return uniqueBackends.values(); }
private void sendWorkToShards(LuceneWork work, boolean forceAsync) { final Class<?> entityType = work.getEntityClass(); EntityIndexBinding entityIndexBinding = searchFactoryImplementor.getIndexBinding(entityType); IndexShardingStrategy shardingStrategy = entityIndexBinding.getSelectionStrategy(); if (forceAsync) { work.getWorkDelegate(StreamingSelectionVisitor.INSTANCE) .performStreamOperation(work, shardingStrategy, progressMonitor, forceAsync); } else { WorkQueuePerIndexSplitter workContext = new WorkQueuePerIndexSplitter(); work.getWorkDelegate(TransactionalSelectionVisitor.INSTANCE) .performOperation(work, shardingStrategy, workContext); workContext.commitOperations( progressMonitor); // FIXME I need a "Force sync" actually for when using PurgeAll before // the indexing starts } }
@Test public void testDynamicCreationOfShards() throws Exception { EntityIndexBinding entityIndexBinding = getExtendedSearchIntegrator().getIndexBindings().get(Animal.class); assertThat(entityIndexBinding.getIndexManagers()).hasSize(0); insertAnimals(elephant); assertThat(entityIndexBinding.getIndexManagers()).hasSize(1); insertAnimals(spider); assertThat(entityIndexBinding.getIndexManagers()).hasSize(2); insertAnimals(bear); assertThat(entityIndexBinding.getIndexManagers()).hasSize(2); assertEquals(2, getNumberOfDocumentsInIndex("Animal.Mammal")); assertEquals(1, getNumberOfDocumentsInIndex("Animal.Insect")); }
@Override public IndexReader open(Class<?>... entities) { if (entities.length == 0) { throw log.needAtLeastOneIndexedEntityType(); } HashMap<String, IndexManager> indexManagers = new HashMap<String, IndexManager>(); for (Class<?> type : entities) { EntityIndexBinding entityIndexBinding = searchFactory.getSafeIndexBindingForEntity(type); IndexManager[] indexManagersForAllShards = entityIndexBinding.getSelectionStrategy().getIndexManagersForAllShards(); for (IndexManager im : indexManagersForAllShards) { indexManagers.put(im.getIndexName(), im); } } IndexManager[] uniqueIndexManagers = indexManagers.values().toArray(new IndexManager[indexManagers.size()]); return MultiReaderFactory.openReader(uniqueIndexManagers); }
@Override public IndexedTypeDescriptor getIndexedTypeDescriptor(Class<?> entityType) { IndexedTypeDescriptor typeDescriptor; if (indexedTypeDescriptors.containsKey(entityType)) { typeDescriptor = indexedTypeDescriptors.get(entityType); } else { EntityIndexBinding indexBinder = indexBindingForEntities.get(entityType); IndexedTypeDescriptor indexedTypeDescriptor; if (indexBinder == null) { indexedTypeDescriptor = new IndexedTypeDescriptorForUnindexedType(entityType); } else { indexedTypeDescriptor = new IndexedTypeDescriptorImpl( indexBinder.getDocumentBuilder().getMetadata(), indexBinder.getIndexManagers()); } indexedTypeDescriptors.put(entityType, indexedTypeDescriptor); typeDescriptor = indexedTypeDescriptor; } return typeDescriptor; }
@Override public Analyzer getAnalyzer(Class<?> clazz) { EntityIndexBinding entityIndexBinding = getSafeIndexBindingForEntity(clazz); DocumentBuilderIndexedEntity builder = entityIndexBinding.getDocumentBuilder(); return builder.getAnalyzer(); }
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: case DELETE_BY_QUERY: 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.getTenantIdentifier(), 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.getTenantIdentifier(), work.getEntity(), work.getId(), WorkType.DELETE, work.isIdentifierWasRolledBack()); log.forceRemoveOnIndexOperationViaInterception(entityClass, work.getType()); break; default: throw new AssertionFailure("Unknown action type: " + operation); } return result; }