com.alachisoft.ncache.client.internal.communication.SocketManagerHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ncache-professional-client Show documentation
Show all versions of ncache-professional-client Show documentation
NCache Professional client for java.
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){}
}
}
}