/* * Copyright (c) 2015-2019, David A. Bauer. All rights reserved. * * Licensed 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 io.actor4j.core; import static io.actor4j.core.utils.ActorUtils.isDirective; import java.util.ArrayDeque; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; import org.apache.commons.collections4.queue.CircularFifoQueue; import org.jctools.queues.MpscArrayQueue; import org.jctools.queues.MpscLinkedQueue8; import io.actor4j.core.messages.ActorMessage; public class XActorThread extends ActorThread { protected final Queue<ActorMessage<?>> directiveQueue; protected final Queue<ActorMessage<?>> priorityQueue; protected final Queue<ActorMessage<?>> innerQueueL2; protected final Queue<ActorMessage<?>> innerQueueL1; protected final Queue<ActorMessage<?>> outerQueueL2B; protected final Queue<ActorMessage<?>> outerQueueL2A; protected final Queue<ActorMessage<?>> outerQueueL1; protected final Queue<ActorMessage<?>> serverQueueL2; protected final Queue<ActorMessage<?>> serverQueueL1; protected final XAntiFloodingTimer innerQueueAntiFloodingTimer; protected final XAntiFloodingTimer outerQueueAntiFloodingTimer; protected final AtomicBoolean newMessage; public XActorThread(ThreadGroup group, String name, ActorSystemImpl system) { super(group, name, system); directiveQueue = new MpscArrayQueue<>(system.getQueueSize()); priorityQueue = new PriorityBlockingQueue<>(system.getQueueSize()); serverQueueL2 = new MpscArrayQueue<>(system.getQueueSize()); serverQueueL1 = new ArrayDeque<>(system.getBufferQueueSize()); outerQueueL2B = new MpscLinkedQueue8<>(); outerQueueL2A = new MpscArrayQueue<>(system.getQueueSize()); outerQueueL1 = new ArrayDeque<>(system.getBufferQueueSize()); innerQueueL2 = new LinkedList<>(); innerQueueL1 = new CircularFifoQueue<>(system.getQueueSize()); innerQueueAntiFloodingTimer = ((XActorSystemImpl)system).factoryAntiFloodingTimer.get(); outerQueueAntiFloodingTimer = ((XActorSystemImpl)system).factoryAntiFloodingTimer.get(); newMessage = new AtomicBoolean(true); } @Override public void directiveQueue(ActorMessage<?> message) { directiveQueue.offer(message); } @Override public void priorityQueue(ActorMessage<?> message) { priorityQueue.offer(message); } @Override public void serverQueue(ActorMessage<?> message) { serverQueueL2.offer(message); } @Override public void outerQueue(ActorMessage<?> message) { if (!((XActorSystemImpl)system).antiFloodingEnabled.get()) { if (outerQueueL2A.size()>=system.getQueueSize() || !outerQueueL2B.isEmpty()) { if (isDirective(message) || outerQueueAntiFloodingTimer.isInTimeRange()) outerQueueL2B.offer(message); } else { outerQueueAntiFloodingTimer.inactive(); outerQueueL2A.offer(message); } } else outerQueueL2A.offer(message); } @Override public void innerQueue(ActorMessage<?> message) { if (!((XActorSystemImpl)system).antiFloodingEnabled.get()) { if ((((CircularFifoQueue<ActorMessage<?>>)innerQueueL1).isAtFullCapacity() || !innerQueueL2.isEmpty())) { if (isDirective(message) || innerQueueAntiFloodingTimer.isInTimeRange()) innerQueueL2.offer(message); } else { innerQueueAntiFloodingTimer.inactive(); innerQueueL1.offer(message); } } else innerQueueL1.offer(message); } @Override public void onRun() { boolean hasNextDirective; boolean hasNextPriority; int hasNextServer; int hasNextOuter; int hasNextInner; int idle = 0; while (!isInterrupted()) { hasNextDirective = false; hasNextPriority = false; hasNextServer = 0; hasNextOuter = 0; hasNextInner = 0; while (poll(directiveQueue)) hasNextDirective=true; while (poll(priorityQueue)) hasNextPriority=true; if (system.clientMode) { for (; hasNextServer<system.throughput && poll(serverQueueL1); hasNextServer++); if (hasNextServer<system.throughput && serverQueueL2.peek()!=null) { ActorMessage<?> message = null; for (int j=0; j<system.getBufferQueueSize() && (message=serverQueueL2.poll())!=null; j++) serverQueueL1.offer(message); for (; hasNextServer<system.throughput && poll(serverQueueL1); hasNextServer++); } } for (; hasNextOuter<system.throughput && poll(outerQueueL1); hasNextOuter++); if (hasNextOuter<system.throughput && outerQueueL2A.peek()!=null) { ActorMessage<?> message = null; for (int j=0; j<system.getBufferQueueSize() && (message=outerQueueL2A.poll())!=null; j++) outerQueueL1.offer(message); for (; hasNextOuter<system.throughput && poll(outerQueueL1); hasNextOuter++); } if (hasNextOuter<system.throughput && outerQueueL2B.peek()!=null) { ActorMessage<?> message = null; for (int j=0; j<system.getBufferQueueSize() && (message=outerQueueL2B.poll())!=null; j++) outerQueueL1.offer(message); for (; hasNextOuter<system.throughput && poll(outerQueueL1); hasNextOuter++); } for (; hasNextInner<system.throughput && poll(innerQueueL1); hasNextInner++); if (hasNextInner<system.throughput && innerQueueL2.peek()!=null) { ActorMessage<?> message = null; for (int j=0; j<system.getQueueSize() && (message=innerQueueL2.poll())!=null; j++) innerQueueL1.offer(message); for (; hasNextInner<system.throughput && poll(innerQueueL1); hasNextInner++); } if (hasNextInner==0 && hasNextOuter==0 && hasNextServer==0 && !hasNextPriority && !hasNextDirective) { idle++; if (idle>system.idle) { idle = 0; if (system.threadMode==ActorThreadMode.PARK) { if (newMessage.compareAndSet(true, false)) LockSupport.park(this); } else if (system.threadMode==ActorThreadMode.SLEEP) { try { sleep(system.sleepTime); } catch (InterruptedException e) { interrupt(); } } else yield(); } } else idle = 0; } } @Override protected void newMessage() { if (system.threadMode==ActorThreadMode.PARK && newMessage.compareAndSet(false, true)) LockSupport.unpark(this); } @Override public Queue<ActorMessage<?>> getDirectiveQueue() { return directiveQueue; } @Override public Queue<ActorMessage<?>> getPriorityQueue() { return priorityQueue; } @Override public Queue<ActorMessage<?>> getServerQueue() { return serverQueueL2; } @Override public Queue<ActorMessage<?>> getOuterQueue() { return outerQueueL2A; } @Override public Queue<ActorMessage<?>> getInnerQueue() { return innerQueueL1; } }