/*
* Copyright 1999-2012 Alibaba Group.
*
* 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 fm.liu.timo.net;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import fm.liu.timo.net.buffer.BufferPool;
import fm.liu.timo.net.connection.AbstractConnection;
import fm.liu.timo.net.connection.BackendConnection;
import fm.liu.timo.net.connection.FrontendConnection;
import fm.liu.timo.net.connection.NIOConnection;
import fm.liu.timo.statistic.CommandCount;
import fm.liu.timo.util.ExecutorUtil;
import fm.liu.timo.util.TimeUtil;
/**
* @author xianmao.hexm
*/
public final class NIOProcessor {
private static final int DEFAULT_BUFFER_SIZE = 1024 * 1024 * 16;
private static final int DEFAULT_BUFFER_CHUNK_SIZE = 4096;
private static final int AVAILABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
private final String name;
private final NIOReactor reactor;
private final BufferPool bufferPool;
private final ExecutorService executor;
private final ConcurrentMap<Long, FrontendConnection> frontends;
private final ConcurrentMap<Long, BackendConnection> backends;
private final CommandCount commands;
private long netInBytes;
private long netOutBytes;
private int queryTimeout;
public NIOProcessor(String name) throws IOException {
this(name, DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_CHUNK_SIZE, AVAILABLE_PROCESSORS,
AVAILABLE_PROCESSORS);
}
public NIOProcessor(String name, int handler, int executor, int queryTimeout)
throws IOException {
this(name, DEFAULT_BUFFER_SIZE, DEFAULT_BUFFER_CHUNK_SIZE, handler, executor);
this.queryTimeout = queryTimeout;
}
public NIOProcessor(String name, int buffer, int chunk, int handler, int executor)
throws IOException {
this.name = name;
this.reactor = new NIOReactor(name);
this.bufferPool = new BufferPool(buffer, chunk);
this.executor = (executor > 0) ? ExecutorUtil.create(name + "-E", executor) : null;
this.frontends = new ConcurrentHashMap<Long, FrontendConnection>();
this.backends = new ConcurrentHashMap<Long, BackendConnection>();
this.commands = new CommandCount();
}
public String getName() {
return name;
}
public BufferPool getBufferPool() {
return bufferPool;
}
public int getRegisterQueueSize() {
return reactor.getRegisterQueue().size();
}
public int getWriteQueueSize() {
int total = 0;
for (FrontendConnection fron : frontends.values()) {
total += fron.getWriteQueue().size();
}
for (BackendConnection back : backends.values()) {
total += back.getWriteQueue().size();
}
return total;
}
public ExecutorService getExecutor() {
return executor;
}
public void startup() {
reactor.startup();
}
public void postRegister(AbstractConnection c) {
reactor.postRegister(c);
}
public CommandCount getCommands() {
return commands;
}
public long getNetInBytes() {
return netInBytes;
}
public void addNetInBytes(long bytes) {
netInBytes += bytes;
}
public long getNetOutBytes() {
return netOutBytes;
}
public void addNetOutBytes(long bytes) {
netOutBytes += bytes;
}
public long getReactCount() {
return reactor.getReactCount();
}
public void addFrontend(FrontendConnection c) {
frontends.put(c.getId(), c);
}
public ConcurrentMap<Long, FrontendConnection> getFrontends() {
return frontends;
}
public void addBackend(BackendConnection c) {
backends.put(c.getID(), c);
}
public ConcurrentMap<Long, BackendConnection> getBackends() {
return backends;
}
/**
* 定时执行该方法,回收部分资源。
*/
public void check() {
frontendCheck();
backendCheck();
}
// 前端连接检查
private void frontendCheck() {
Iterator<Entry<Long, FrontendConnection>> it = frontends.entrySet().iterator();
while (it.hasNext()) {
FrontendConnection c = it.next().getValue();
// 删除空连接
if (c == null) {
it.remove();
continue;
}
// 清理已关闭连接,否则空闲超时检查。
if (c.isClosed()) {
it.remove();
c.cleanup();
} else {
// 空闲超时检查
if (TimeUtil.currentTimeMillis() - c.getVariables().getLastActiveTime() > c
.getIdleTimeout()) {
c.close("idle timeout");
}
}
}
}
// 后端连接检查
private void backendCheck() {
Iterator<Entry<Long, BackendConnection>> it = backends.entrySet().iterator();
while (it.hasNext()) {
BackendConnection c = it.next().getValue();
// 删除空连接
if (c == null) {
it.remove();
continue;
}
// 查询超时检查。
if (c.isRunning() && TimeUtil.currentTimeMillis()
- c.getVariables().getLastActiveTime() > queryTimeout) {
c.close("query timeout");
}
// 清理已关闭连接
if (c.isClosed()) {
it.remove();
c.cleanup();
}
}
}
public NIOReactor getReactor() {
return reactor;
}
public void remove(NIOConnection con) {
if (con instanceof FrontendConnection) {
frontends.remove(con.getID());
} else {
backends.remove(con.getID());
}
}
}