io.questdb.network.IODispatcherWindows Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core Show documentation
Show all versions of core Show documentation
QuestDB is High Performance Time Series Database
/*******************************************************************************
* ___ _ ____ ____
* / _ \ _ _ ___ ___| |_| _ \| __ )
* | | | | | | |/ _ \/ __| __| | | | _ \
* | |_| | |_| | __/\__ \ |_| |_| | |_) |
* \__\_\\__,_|\___||___/\__|____/|____/
*
* Copyright (c) 2014-2019 Appsicle
* Copyright (c) 2019-2020 QuestDB
*
* 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.questdb.network;
import io.questdb.std.LongIntHashMap;
import io.questdb.std.Unsafe;
public class IODispatcherWindows extends AbstractIODispatcher {
private static final int M_OPERATION = 2;
private final FDSet readFdSet;
private final FDSet writeFdSet;
private final LongIntHashMap fds = new LongIntHashMap();
private final SelectFacade sf;
public IODispatcherWindows(
IODispatcherConfiguration configuration,
IOContextFactory ioContextFactory
) {
super(configuration, ioContextFactory);
this.readFdSet = new FDSet(configuration.getEventCapacity());
this.writeFdSet = new FDSet(configuration.getEventCapacity());
this.sf = configuration.getSelectFacade();
final int r = pending.addRow();
pending.set(r, M_TIMESTAMP, clock.getTicks());
pending.set(r, M_FD, serverFd);
pending.set(r, M_OPERATION, IOOperation.READ);
readFdSet.add(serverFd);
readFdSet.setCount(1);
writeFdSet.setCount(0);
logSuccess(configuration);
}
@Override
public void close() {
super.close();
readFdSet.close();
writeFdSet.close();
LOG.info().$("closed").$();
}
@Override
protected void pendingAdded(int index) {
pending.set(index, M_OPERATION, initialBias == IODispatcherConfiguration.BIAS_READ ? IOOperation.READ : IOOperation.WRITE);
}
private boolean processRegistrations(long timestamp) {
long cursor;
boolean useful = false;
while ((cursor = interestSubSeq.next()) > -1) {
useful = true;
IOEvent evt = interestQueue.get(cursor);
C context = evt.context;
int operation = evt.operation;
interestSubSeq.done(cursor);
int r = pending.addRow();
pending.set(r, M_TIMESTAMP, timestamp);
pending.set(r, M_FD, context.getFd());
pending.set(r, M_OPERATION, operation);
pending.set(r, context);
}
return useful;
}
private void queryFdSets(long timestamp) {
for (int i = 0, n = readFdSet.getCount(); i < n; i++) {
long fd = readFdSet.get(i);
if (fd == serverFd) {
accept(timestamp);
} else {
fds.put(fd, SelectAccessor.FD_READ);
}
}
// collect writes into hash map
for (int i = 0, n = writeFdSet.getCount(); i < n; i++) {
final long fd = writeFdSet.get(i);
final int index = fds.keyIndex(fd);
if (fds.valueAt(index) == -1) {
fds.putAt(index, fd, SelectAccessor.FD_WRITE);
} else {
fds.putAt(index, fd, SelectAccessor.FD_READ | SelectAccessor.FD_WRITE);
}
}
}
@Override
protected boolean runSerially() {
processDisconnects();
int count = sf.select(readFdSet.address, writeFdSet.address, 0);
if (count < 0) {
LOG.error().$("Error in select(): ").$(nf.errno()).$();
return false;
}
final long timestamp = clock.getTicks();
boolean useful = false;
fds.clear();
// collect reads into hash map
if (count > 0) {
queryFdSets(timestamp);
useful = true;
}
// process returned fds
useful = processRegistrations(timestamp) | useful;
// re-arm select() fds
int readFdCount = 0;
int writeFdCount = 0;
readFdSet.reset();
writeFdSet.reset();
long deadline = timestamp - idleConnectionTimeout;
for (int i = 0, n = pending.size(); i < n; ) {
final long ts = pending.get(i, M_TIMESTAMP);
final long fd = pending.get(i, M_FD);
final int _new_op = fds.get(fd);
if (_new_op == -1) {
// check if expired
if (ts < deadline && fd != serverFd) {
doDisconnect(pending.get(i));
pending.deleteRow(i);
n--;
useful = true;
continue;
}
if (pending.get(i++, M_OPERATION) == IOOperation.READ) {
readFdSet.add(fd);
readFdCount++;
} else {
writeFdSet.add(fd);
writeFdCount++;
}
} else {
// this fd just has fired
// publish event
// and remove from pending
final C context = pending.get(i);
if ((_new_op & SelectAccessor.FD_READ) > 0) {
publishOperation(IOOperation.READ, context);
}
if ((_new_op & SelectAccessor.FD_WRITE) > 0) {
publishOperation(IOOperation.WRITE, context);
}
pending.deleteRow(i);
n--;
}
}
readFdSet.setCount(readFdCount);
writeFdSet.setCount(writeFdCount);
return useful;
}
private static class FDSet {
private long address;
private int size;
private long _wptr;
private long lim;
private FDSet(int size) {
int l = SelectAccessor.ARRAY_OFFSET + 8 * size;
this.address = Unsafe.malloc(l);
this.size = size;
this._wptr = address + SelectAccessor.ARRAY_OFFSET;
this.lim = address + l;
}
private void add(long fd) {
if (_wptr == lim) {
resize();
}
long p = _wptr;
Unsafe.getUnsafe().putLong(p, fd);
_wptr = p + 8;
}
private void close() {
if (address != 0) {
Unsafe.free(address, lim - address);
address = 0;
}
}
private long get(int index) {
return Unsafe.getUnsafe().getLong(address + SelectAccessor.ARRAY_OFFSET + index * 8L);
}
private int getCount() {
return Unsafe.getUnsafe().getInt(address + SelectAccessor.COUNT_OFFSET);
}
private void setCount(int count) {
Unsafe.getUnsafe().putInt(address + SelectAccessor.COUNT_OFFSET, count);
}
private void reset() {
_wptr = address + SelectAccessor.ARRAY_OFFSET;
}
private void resize() {
int sz = size * 2;
int l = SelectAccessor.ARRAY_OFFSET + 8 * sz;
long _addr = Unsafe.malloc(l);
Unsafe.getUnsafe().copyMemory(address, _addr, lim - address);
Unsafe.free(address, lim - address);
lim = _addr + l;
size = sz;
_wptr = _addr + (_wptr - address);
address = _addr;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy