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

com.alachisoft.ncache.client.internal.communication.SocketManagerHandler Maven / Gradle / Ivy

There is a newer version: 5.3.0
Show newest version
package com.alachisoft.ncache.client.internal.communication;

import Alachisoft.NCache.Common.Threading.Monitor;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class SocketManagerHandler implements AutoCloseable{
    private final ExecutorService executorService = Executors.newFixedThreadPool(25);
    private final java.util.LinkedList writeQueue = new java.util.LinkedList();
    private boolean _enablePipelining = false;
    private Thread _dedicatedWriter = null;
    private Broker _encloser;
    private Thread _thresholdRefresher= null;

    public boolean isEnablePipelining() {
        return _enablePipelining;
    }

    public void setEnablePipelining(boolean enablePipelining) {
        this._enablePipelining = enablePipelining;
    }

    public SocketManagerHandler(Broker encloser) {
        _encloser = encloser;

    }

    public final void StartSocketManager(boolean useHighPrioritySocketThreads) {
        _dedicatedWriter = new Thread(() -> WriteAllQueues()); // don't need a huge stack;
        _dedicatedWriter.setPriority(useHighPrioritySocketThreads ? 10 : 5);
        _dedicatedWriter.setName(getClass().getName() + ":Write");
        _dedicatedWriter.setDaemon(true); // should not keep process alive
        _dedicatedWriter.start(); // will self-exit when disposed
    }

    public final void StartPipelining() {
        _thresholdRefresher = new Thread(() -> UpdateBulkThreshold());
        _thresholdRefresher.setName("ThresholdRefresher");
        _thresholdRefresher.setDaemon(true); // should not keep process alive
        _thresholdRefresher.start();
    }

    private void UpdateBulkThreshold() {
        try {
            while (!_encloser.getIsDisposing()) {
                try {
                    if (_encloser.getPool() != null) {
                        _encloser.getPool().UpdateBulkThreshold();
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    break;
                } catch (Exception e) {
                    if (_encloser.getLogger().getIsErrorLogsEnabled()) {
                        _encloser.getLogger().getNCacheLog().Error("Broker.UpdateBulkThreshold", "Problem occured while updating bulk threshold. " + e.toString());
                    }
                    break;
                }
            }
        } catch (Exception ex) {
            if (_encloser.getLogger().getIsErrorLogsEnabled()) {
                _encloser.getLogger().getNCacheLog().Error("Broker.UpdateBulkThreshold", "Problem occured while updating bulk threshold. " + ex.toString());
            }
        }
    }

    private void WriteAllQueues() {
        while (true) {
            try {
                Connection connection;
                synchronized (writeQueue) {
                    if (writeQueue.isEmpty()) {
                        if (_encloser.getIsDisposing()) // <========= exit point
                        {
                            break;
                        }
                        Monitor.wait(writeQueue);
                        if (_encloser.getIsDisposing()) // (woken by Dispose)
                        {
                            break;
                        }
                        if (writeQueue.isEmpty()) // still nothing...
                        {
                            continue;
                        }
                    }
                    //connection = writeQueue.WaitedDequeue(_clientConfig.EnablePipelining);
                    connection = writeQueue.poll();
                }

                if (isEnablePipelining()) {
                    connection.WaitUntillPipelineFilled();
                }

                switch (connection.WriteQueue(200)) {
                    case MoreWork:
                    case QueueEmptyAfterWrite:
                        // back of the line!
                        synchronized (writeQueue) {
                            writeQueue.offer(connection);
                        }
                        break;
                    case CompetingWriter:
                        break;
                    case NoConnection:
                        connection.getInWriteQueue().set(0);
                        break;
                    case NothingToDo:
                        if (!connection.ConfirmRemoveFromWriteQueue()) { // more snuck in; back of the line!
                            synchronized (writeQueue) {
                                writeQueue.offer(connection);
                            }
                        }
                        break;
                }
            } catch (InterruptedException e) {
                break;
            } catch (Exception e) {
                if (_encloser.getLogger() != null && _encloser.getLogger().getIsErrorLogsEnabled()) {
                    _encloser.getLogger().getNCacheLog().Error("Broker.DedicatedWriter", e.toString());
                }
            }
        }
    }


    public final void RequestWrite(Connection connection, boolean forced) {
        int resultvalue = connection.getInWriteQueue().compareAndExchange(0, 1);

        if (resultvalue == 0 || forced) {
            synchronized (writeQueue) {
                writeQueue.offer(connection);
                if (writeQueue.size() == 1) {
                Monitor.pulse(writeQueue);
                } else if (writeQueue.size() >= 2) { // struggling are we? let's have some help dealing with the backlog
                   executorService.execute(() -> writeOneQueue());
               }
            }
        }
    }

    private void writeOneQueue() {
        Connection connection;
        synchronized (writeQueue) {
            connection = writeQueue.isEmpty() ? null : writeQueue.poll();
        }
        if (connection == null) {
            return;
        }
        boolean keepGoing;
        do {
            if (isEnablePipelining()) {
                connection.WaitUntillPipelineFilled();
            }

            switch (connection.WriteQueue(-1)) {
                case MoreWork:
                case QueueEmptyAfterWrite:
                    keepGoing = true;
                    break;
                case NothingToDo:
                    keepGoing = !connection.ConfirmRemoveFromWriteQueue();
                    break;
                case CompetingWriter:
                    keepGoing = false;
                    break;
                case NoConnection:
                    connection.getInWriteQueue().set(0);
                    keepGoing = false;
                    break;
                default:
                    keepGoing = false;
                    break;
            }
        } while (keepGoing);
    }

    public final void StopWriter() {
        if (_dedicatedWriter != null && _dedicatedWriter.isAlive()) {
            _dedicatedWriter.interrupt();
        }



    }

    @Override
    public void close() throws Exception {
        StopWriter();

        if (_thresholdRefresher != null && _thresholdRefresher.isAlive()) {
            _thresholdRefresher.interrupt();
        }

        if(executorService !=null)
            awaitTerminationAfterShutdown(executorService);
    }


    public void awaitTerminationAfterShutdown(ExecutorService threadPool) {
        try {
            threadPool.shutdown();

            if (!threadPool.awaitTermination(15, TimeUnit.SECONDS)) {
                threadPool.shutdownNow();
            }
        } catch (InterruptedException ex) {
           try {
               threadPool.shutdownNow();
               Thread.currentThread().interrupt();
           }catch (Exception e){}
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy