<commit_before>/*
 * 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.usergrid.persistence.core.executor;


import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;


/**
 * A task executor that allows you to submit tasks
 */
public class TaskExecutorFactory {

    public enum RejectionAction {
        ABORT,
        CALLERRUNS
    }
    /**
     * Create a task executor
     * @param schedulerName
     * @param maxThreadCount
     * @param maxQueueSize
     * @return
     */
    public static ThreadPoolExecutor createTaskExecutor( final String schedulerName, final int maxThreadCount,
                                                         final int maxQueueSize, RejectionAction rejectionAction ) {


        final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>( maxQueueSize );


        if(rejectionAction.equals(RejectionAction.ABORT)){

            return new MaxSizeThreadPool( queue, schedulerName, maxThreadCount );

        }
        else if(rejectionAction.equals(RejectionAction.CALLERRUNS)){

            return new MaxSizeThreadPoolCallerRuns( queue, schedulerName, maxThreadCount );

        }else{
            //default to the thread pool with ABORT policy
            return new MaxSizeThreadPool( queue, schedulerName, maxThreadCount );
        }

    }

    /**
     * Create a thread pool that will reject work if our audit tasks become overwhelmed
     */
    private static final class MaxSizeThreadPool extends ThreadPoolExecutor {

        public MaxSizeThreadPool( final BlockingQueue<Runnable> queue, final String poolName, final int maxPoolSize ) {
            super( maxPoolSize, maxPoolSize, 30, TimeUnit.SECONDS, queue, new CountingThreadFactory( poolName ) );
        }
    }

    /**
     * Create a thread pool that will implement CallerRunsPolicy if our tasks become overwhelmed
     */
    private static final class MaxSizeThreadPoolCallerRuns extends ThreadPoolExecutor {

        public MaxSizeThreadPoolCallerRuns( final BlockingQueue<Runnable> queue, final String poolName, final int maxPoolSize ) {
            super( maxPoolSize, maxPoolSize, 30, TimeUnit.SECONDS, queue,
                new CountingThreadFactory( poolName ), new ThreadPoolExecutor.CallerRunsPolicy() );
        }
    }


    /**
     * Thread factory that will name and count threads for easier debugging
     */
    private static final class CountingThreadFactory implements ThreadFactory {

        private final AtomicLong threadCounter = new AtomicLong();
        private final String poolName;


        private CountingThreadFactory( final String poolName ) {this.poolName = poolName;}


        @Override
        public Thread newThread( final Runnable r ) {
            final long newValue = threadCounter.incrementAndGet();

            final String threadName = poolName + "-" + newValue;

            Thread t = new Thread( r, threadName );

            //set it to be a daemon thread so it doesn't block shutdown
            t.setDaemon( true );

            return t;
        }
    }
}<commit_msg>Add custom rejection handler that implements 'caller runs' which includes logging.<commit_after>/*
 * 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.usergrid.persistence.core.executor;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;


/**
 * A task executor that allows you to submit tasks
 */
public class TaskExecutorFactory {

    private static final Logger log = LoggerFactory.getLogger(TaskExecutorFactory.class);

    public enum RejectionAction {
        ABORT,
        CALLERRUNS
    }
    /**
     * Create a task executor
     * @param schedulerName
     * @param maxThreadCount
     * @param maxQueueSize
     * @return
     */
    public static ThreadPoolExecutor createTaskExecutor( final String schedulerName, final int maxThreadCount,
                                                         final int maxQueueSize, RejectionAction rejectionAction ) {


        final BlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>( maxQueueSize );


        if(rejectionAction.equals(RejectionAction.ABORT)){

            return new MaxSizeThreadPool( queue, schedulerName, maxThreadCount );

        }
        else if(rejectionAction.equals(RejectionAction.CALLERRUNS)){

            return new MaxSizeThreadPoolCallerRuns( queue, schedulerName, maxThreadCount );

        }else{
            //default to the thread pool with ABORT policy
            return new MaxSizeThreadPool( queue, schedulerName, maxThreadCount );
        }

    }

    /**
     * Create a thread pool that will reject work if our audit tasks become overwhelmed
     */
    private static final class MaxSizeThreadPool extends ThreadPoolExecutor {

        public MaxSizeThreadPool( final BlockingQueue<Runnable> queue, final String poolName, final int maxPoolSize ) {
            super( maxPoolSize, maxPoolSize, 30, TimeUnit.SECONDS, queue, new CountingThreadFactory( poolName ) );
        }
    }

    /**
     * Create a thread pool that will implement CallerRunsPolicy if our tasks become overwhelmed
     */
    private static final class MaxSizeThreadPoolCallerRuns extends ThreadPoolExecutor {

        public MaxSizeThreadPoolCallerRuns( final BlockingQueue<Runnable> queue, final String poolName, final int maxPoolSize ) {
            super( maxPoolSize, maxPoolSize, 30, TimeUnit.SECONDS, queue,
                new CountingThreadFactory( poolName ), new RejectedHandler(poolName) );
        }
    }


    /**
     * Thread factory that will name and count threads for easier debugging
     */
    private static final class CountingThreadFactory implements ThreadFactory {

        private final AtomicLong threadCounter = new AtomicLong();
        private final String poolName;


        private CountingThreadFactory( final String poolName ) {this.poolName = poolName;}


        @Override
        public Thread newThread( final Runnable r ) {
            final long newValue = threadCounter.incrementAndGet();

            final String threadName = poolName + "-" + newValue;

            Thread t = new Thread( r, threadName );

            //set it to be a daemon thread so it doesn't block shutdown
            t.setDaemon(true);

            return t;
        }
    }

    /**
     * The handler that will handle rejected executions and signal the interface
     */
    private static final class RejectedHandler implements RejectedExecutionHandler {

        private final String poolName;

        private RejectedHandler (final String poolName) {this.poolName = poolName;}

        @Override
        public void rejectedExecution( final Runnable r, final ThreadPoolExecutor executor ) {
            log.warn( "{} task queue full, rejecting task {} and running in thread {}", poolName, r, Thread.currentThread().getName() );

            //We've decided we want to have a "caller runs" policy, to just invoke the task when rejected

            r.run();
        }

    }
}
{'fraction_non_alphanumeric': 0.06635556567266106, 'fraction_numerical': 0.002048713862963806, 'mean_word_length': 2.8387942332896463, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2411138', 'n_tokens_mistral': 2221, 'n_tokens_neox': 2116, 'n_words': 805}