Search in sources :

Example 1 with TraceableThreadFactory

use of org.alfresco.util.TraceableThreadFactory in project alfresco-repository by Alfresco.

the class ChainingUserRegistrySynchronizer method synchronizeInternal.

private void synchronizeInternal(boolean forceUpdate, boolean isFullSync, final boolean splitTxns) {
    if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled()) {
        if (forceUpdate) {
            ChainingUserRegistrySynchronizer.logger.debug("Running a full sync.");
        } else {
            ChainingUserRegistrySynchronizer.logger.debug("Running a differential sync.");
        }
        if (allowDeletions) {
            ChainingUserRegistrySynchronizer.logger.debug("deletions are allowed");
        } else {
            ChainingUserRegistrySynchronizer.logger.debug("deletions are not allowed");
        }
        // Don't proceed with the sync if the repository is read only
        if (this.transactionService.isReadOnly()) {
            ChainingUserRegistrySynchronizer.logger.warn("Unable to proceed with user registry synchronization. Repository is read only.");
            return;
        }
    }
    // Don't proceed with the sync if the repository is read only
    if (this.transactionService.isReadOnly()) {
        ChainingUserRegistrySynchronizer.logger.warn("Unable to proceed with user registry synchronization. Repository is read only.");
        return;
    }
    // Create a background executor that will refresh our lock. This means we can request a lock with a relatively
    // small persistence time and not worry about it lasting after server restarts. Note we use an independent
    // executor because this is a compound operation that spans accross multiple batch processors.
    String lockToken = null;
    TraceableThreadFactory threadFactory = new TraceableThreadFactory();
    threadFactory.setNamePrefix("ChainingUserRegistrySynchronizer lock refresh");
    threadFactory.setThreadDaemon(true);
    ScheduledExecutorService lockRefresher = new ScheduledThreadPoolExecutor(1, threadFactory);
    // Let's ensure all exceptions get logged
    try {
        // First, try to obtain a lock to ensure we are the only node trying to run this job
        try {
            if (splitTxns) {
                // If this is an automated sync on startup or scheduled sync, don't even wait around for the lock.
                // Assume the sync will be completed on another node.
                lockToken = this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<String>() {

                    public String execute() throws Throwable {
                        return ChainingUserRegistrySynchronizer.this.jobLockService.getLock(ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL, 0, 1);
                    }
                }, false, splitTxns);
            } else {
                // If this is a login-triggered sync, give it a few retries before giving up
                lockToken = this.jobLockService.getLock(ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL, 3000, 10);
            }
        } catch (LockAcquisitionException e) {
            // Don't proceed with the sync if it is running on another node
            ChainingUserRegistrySynchronizer.logger.warn("User registry synchronization already running in another thread. Synchronize aborted");
            return;
        }
        // Schedule the lock refresh to run at regular intervals
        final String token = lockToken;
        lockRefresher.scheduleAtFixedRate(new Runnable() {

            public void run() {
                ChainingUserRegistrySynchronizer.this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() {

                    public Object execute() throws Throwable {
                        ChainingUserRegistrySynchronizer.this.jobLockService.refreshLock(token, ChainingUserRegistrySynchronizer.LOCK_QNAME, ChainingUserRegistrySynchronizer.LOCK_TTL);
                        return null;
                    }
                }, false, splitTxns);
            }
        }, ChainingUserRegistrySynchronizer.LOCK_TTL / 2, ChainingUserRegistrySynchronizer.LOCK_TTL / 2, TimeUnit.MILLISECONDS);
        Set<String> visitedZoneIds = new TreeSet<String>();
        Collection<String> instanceIds = this.applicationContextManager.getInstanceIds();
        // Work out the set of all zone IDs in the authentication chain so that we can decide which users / groups
        // need 're-zoning'
        Set<String> allZoneIds = new TreeSet<String>();
        for (String id : instanceIds) {
            allZoneIds.add(AuthorityService.ZONE_AUTH_EXT_PREFIX + id);
        }
        // Collect the plugins that we can sync : zoneId, plugin
        Map<String, UserRegistry> plugins = new HashMap<String, UserRegistry>();
        for (String id : instanceIds) {
            UserRegistry plugin;
            try {
                ApplicationContext context = this.applicationContextManager.getApplicationContext(id);
                plugin = (UserRegistry) context.getBean(this.sourceBeanName);
            } catch (RuntimeException e) {
                // The bean doesn't exist or this subsystem won't start. The reason would have been logged. Ignore and continue.
                continue;
            }
            if (!(plugin instanceof ActivateableBean) || ((ActivateableBean) plugin).isActive()) {
                // yes this plugin needs to be synced
                plugins.put(id, plugin);
            }
        }
        /**
         *  Sync starts here
         */
        notifySyncStart(plugins.keySet());
        for (String id : instanceIds) {
            UserRegistry plugin = plugins.get(id);
            if (plugin != null) {
                // If debug is enabled then dump out the contents of the authentication JMX bean
                if (ChainingUserRegistrySynchronizer.logger.isDebugEnabled()) {
                    mbeanServer = (MBeanServerConnection) getApplicationContext().getBean("alfrescoMBeanServer");
                    try {
                        StringBuilder nameBuff = new StringBuilder(200).append("Alfresco:Type=Configuration,Category=Authentication,id1=managed,id2=").append(URLDecoder.decode(id, "UTF-8"));
                        ObjectName name = new ObjectName(nameBuff.toString());
                        if (mbeanServer != null && mbeanServer.isRegistered(name)) {
                            MBeanInfo info = mbeanServer.getMBeanInfo(name);
                            MBeanAttributeInfo[] attributes = info.getAttributes();
                            ChainingUserRegistrySynchronizer.logger.debug(id + " attributes:");
                            for (MBeanAttributeInfo attribute : attributes) {
                                Object value = mbeanServer.getAttribute(name, attribute.getName());
                                ChainingUserRegistrySynchronizer.logger.debug(attribute.getName() + " = " + value);
                            }
                        }
                    } catch (UnsupportedEncodingException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (MalformedObjectNameException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (InstanceNotFoundException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (IntrospectionException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (AttributeNotFoundException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (ReflectionException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (MBeanException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    } catch (IOException e) {
                        if (ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                            ChainingUserRegistrySynchronizer.logger.warn("Exception during logging", e);
                        }
                    }
                }
                // end of debug dump of active JMX bean
                if (ChainingUserRegistrySynchronizer.logger.isInfoEnabled()) {
                    ChainingUserRegistrySynchronizer.logger.info("Synchronizing users and groups with user registry '" + id + "'");
                }
                if (isFullSync && ChainingUserRegistrySynchronizer.logger.isWarnEnabled()) {
                    if (allowDeletions) {
                        ChainingUserRegistrySynchronizer.logger.warn("Some users and groups previously created by synchronization with this user registry may be removed.");
                    } else {
                        ChainingUserRegistrySynchronizer.logger.warn("Deletions are disabled. Users and groups removed from this registry will be logged only and will remain in the repository. Users previously found in a different registry will be moved in the repository rather than recreated.");
                    }
                }
                // Work out whether we should do the work in a separate transaction (it's most performant if we
                // bunch it into small transactions, but if we are doing a sync on login, it has to be the same
                // transaction)
                boolean requiresNew = splitTxns || AlfrescoTransactionSupport.getTransactionReadState() == TxnReadState.TXN_READ_ONLY;
                try {
                    /**
                     * Do the sync with the specified plugin
                     */
                    syncWithPlugin(id, plugin, forceUpdate, isFullSync, requiresNew, visitedZoneIds, allZoneIds);
                    this.applicationEventPublisher.publishEvent(new SynchronizeDirectoryEndEvent(this, id));
                } catch (final RuntimeException e) {
                    notifySyncDirectoryEnd(id, e);
                    throw e;
                }
            }
        // if plugin exists
        }
        // for each instanceId
        // End of successful synchronization here
        notifySyncEnd();
    } catch (final RuntimeException e) {
        notifySyncEnd(e);
        ChainingUserRegistrySynchronizer.logger.error("Synchronization aborted due to error", e);
        throw e;
    } finally {
        // Release the lock if necessary
        if (lockToken != null) {
            // Cancel the lock refresher
            // Because we may hit a perfect storm when trying to interrupt workers in their unsynchronized getTask()
            // method we can't wait indefinitely and may have to retry the shutdown
            int trys = 0;
            do {
                lockRefresher.shutdown();
                try {
                    lockRefresher.awaitTermination(ChainingUserRegistrySynchronizer.LOCK_TTL, TimeUnit.MILLISECONDS);
                } catch (InterruptedException e) {
                }
            } while (!lockRefresher.isTerminated() && trys++ < 3);
            if (!lockRefresher.isTerminated()) {
                lockRefresher.shutdownNow();
                ChainingUserRegistrySynchronizer.logger.error("Failed to shut down lock refresher");
            }
            final String token = lockToken;
            this.transactionService.getRetryingTransactionHelper().doInTransaction(new RetryingTransactionCallback<Object>() {

                public Object execute() throws Throwable {
                    ChainingUserRegistrySynchronizer.this.jobLockService.releaseLock(token, ChainingUserRegistrySynchronizer.LOCK_QNAME);
                    return null;
                }
            }, false, splitTxns);
        }
    }
}
Also used : ScheduledThreadPoolExecutor(java.util.concurrent.ScheduledThreadPoolExecutor) ApplicationContext(org.springframework.context.ApplicationContext) ActivateableBean(org.alfresco.repo.management.subsystems.ActivateableBean) LockAcquisitionException(org.alfresco.repo.lock.LockAcquisitionException) ScheduledExecutorService(java.util.concurrent.ScheduledExecutorService) LDAPUserRegistry(org.alfresco.repo.security.sync.ldap.LDAPUserRegistry) UnsupportedEncodingException(java.io.UnsupportedEncodingException) TraceableThreadFactory(org.alfresco.util.TraceableThreadFactory) IOException(java.io.IOException) RetryingTransactionCallback(org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback)

Example 2 with TraceableThreadFactory

use of org.alfresco.util.TraceableThreadFactory in project SearchServices by Alfresco.

the class DefaultTrackerPoolFactory method create.

@Override
public ThreadPoolExecutor create() {
    // We need a thread factory
    TraceableThreadFactory threadFactory = new TraceableThreadFactory();
    threadFactory.setThreadDaemon(threadDaemon);
    threadFactory.setThreadPriority(threadPriority);
    if (poolName.length() > 0) {
        threadFactory.setNamePrefix(poolName);
    }
    BlockingQueue<Runnable> workQueue;
    if (workQueueSize < 0) {
        // We can have an unlimited queue, as we have a sensible thread pool!
        workQueue = new LinkedBlockingQueue<Runnable>();
    } else {
        // Use an array one for consistent performance on a small queue size
        workQueue = new ArrayBlockingQueue<Runnable>(workQueueSize);
    }
    ThreadPoolExecutor threadPoolExecutor = new DynamicallySizedThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, threadFactory, rejectedExecutionHandler);
    return threadPoolExecutor;
}
Also used : DynamicallySizedThreadPoolExecutor(org.alfresco.util.DynamicallySizedThreadPoolExecutor) TraceableThreadFactory(org.alfresco.util.TraceableThreadFactory) DynamicallySizedThreadPoolExecutor(org.alfresco.util.DynamicallySizedThreadPoolExecutor) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor)

Example 3 with TraceableThreadFactory

use of org.alfresco.util.TraceableThreadFactory in project alfresco-repository by Alfresco.

the class DictionaryLoadDAOTest method initDictionaryCaches.

private void initDictionaryCaches(DictionaryDAOImpl dictionaryDAO, TenantService tenantService) throws Exception {
    CompiledModelsCache compiledModelsCache = new CompiledModelsCache();
    compiledModelsCache.setDictionaryDAO(dictionaryDAO);
    compiledModelsCache.setTenantService(tenantService);
    compiledModelsCache.setRegistry(new DefaultAsynchronouslyRefreshedCacheRegistry());
    TraceableThreadFactory threadFactory = new TraceableThreadFactory();
    threadFactory.setThreadDaemon(true);
    threadFactory.setThreadPriority(Thread.NORM_PRIORITY);
    ThreadPoolExecutor threadPoolExecutor = new DynamicallySizedThreadPoolExecutor(20, 20, 90, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
    compiledModelsCache.setThreadPoolExecutor(threadPoolExecutor);
    dictionaryDAO.setDictionaryRegistryCache(compiledModelsCache);
    dictionaryDAO.init();
}
Also used : DynamicallySizedThreadPoolExecutor(org.alfresco.util.DynamicallySizedThreadPoolExecutor) DefaultAsynchronouslyRefreshedCacheRegistry(org.alfresco.util.cache.DefaultAsynchronouslyRefreshedCacheRegistry) TraceableThreadFactory(org.alfresco.util.TraceableThreadFactory) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) DynamicallySizedThreadPoolExecutor(org.alfresco.util.DynamicallySizedThreadPoolExecutor)

Aggregations

TraceableThreadFactory (org.alfresco.util.TraceableThreadFactory)3 ThreadPoolExecutor (java.util.concurrent.ThreadPoolExecutor)2 DynamicallySizedThreadPoolExecutor (org.alfresco.util.DynamicallySizedThreadPoolExecutor)2 IOException (java.io.IOException)1 UnsupportedEncodingException (java.io.UnsupportedEncodingException)1 ScheduledExecutorService (java.util.concurrent.ScheduledExecutorService)1 ScheduledThreadPoolExecutor (java.util.concurrent.ScheduledThreadPoolExecutor)1 LockAcquisitionException (org.alfresco.repo.lock.LockAcquisitionException)1 ActivateableBean (org.alfresco.repo.management.subsystems.ActivateableBean)1 LDAPUserRegistry (org.alfresco.repo.security.sync.ldap.LDAPUserRegistry)1 RetryingTransactionCallback (org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback)1 DefaultAsynchronouslyRefreshedCacheRegistry (org.alfresco.util.cache.DefaultAsynchronouslyRefreshedCacheRegistry)1 ApplicationContext (org.springframework.context.ApplicationContext)1