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

com.aerospike.client.async.NioConnector Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2012-2023 Aerospike, Inc.
 *
 * Portions may be licensed to Aerospike, Inc. under one or more contributor
 * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
 *
 * 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 com.aerospike.client.async;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;

import com.aerospike.client.AerospikeException;
import com.aerospike.client.ResultCode;
import com.aerospike.client.admin.AdminCommand;
import com.aerospike.client.cluster.Cluster;
import com.aerospike.client.cluster.Node;

/**
 * Create nio connection and place in connection pool.
 * Used for min connections functionality.
 */
public final class NioConnector extends AsyncConnector implements INioCommand {

	private final NioEventLoop eventLoop;
	private ByteBuffer byteBuffer;
	private NioConnection conn;

	public NioConnector(NioEventLoop eventLoop, Cluster cluster, Node node, AsyncConnector.Listener listener) {
		super(eventLoop, cluster, node, listener);
		this.eventLoop = eventLoop;
	}

	@Override
	public void createConnection() {
		state = AsyncCommand.CONNECT;
		conn = new NioConnection(node.getAddress());
		node.connectionOpened(eventLoop.index);
		conn.registerConnect(eventLoop, this);
	}

	@Override
	public void processEvent(SelectionKey key) {
		try {
			int ops = key.readyOps();

			if ((ops & SelectionKey.OP_READ) != 0) {
				read();
			}
			else if ((ops & SelectionKey.OP_WRITE) != 0) {
				write();
			}
			else if ((ops & SelectionKey.OP_CONNECT) != 0) {
				finishConnect();
			}
		}
		catch (AerospikeException ae) {
			fail(ae);
		}
		catch (Throwable e) {
			fail(new AerospikeException(e));
		}
	}

	protected final void finishConnect() throws IOException {
		conn.finishConnect();

		if (cluster.authEnabled) {
			byte[] token = node.getSessionToken();

			if (token != null) {
				writeAuth(token);
				return;
			}
		}

		finish();
	}

	private final void writeAuth(byte[] token) throws IOException {
		state = AsyncCommand.AUTH_WRITE;

		byte[] dataBuffer = new byte[256];
		AdminCommand admin = new AdminCommand(dataBuffer);
		int dataOffset = admin.setAuthenticate(cluster, token);

		byteBuffer = eventLoop.getByteBuffer();
		byteBuffer.clear();
		byteBuffer.put(dataBuffer, 0, dataOffset);
		byteBuffer.flip();

		if (conn.write(byteBuffer)) {
			byteBuffer.clear();
			byteBuffer.limit(8);
			state = AsyncCommand.AUTH_READ_HEADER;
			conn.registerRead();
		}
		else {
			state = AsyncCommand.AUTH_WRITE;
			conn.registerWrite();
		}
	}

	protected final void write() throws IOException {
		if (conn.write(byteBuffer)) {
			byteBuffer.clear();
			byteBuffer.limit(8);
			state = AsyncCommand.AUTH_READ_HEADER;
			conn.registerRead();
		}
	}

	protected final void read() throws IOException {
		if (! conn.read(byteBuffer)) {
			return;
		}

		switch (state) {
		case AsyncCommand.AUTH_READ_HEADER:
			readAuthHeader();
			if (! conn.read(byteBuffer)) {
				return;
			}
			// Fall through to AUTH_READ_BODY

		case AsyncCommand.AUTH_READ_BODY:
			readAuthBody();
			finish();
			break;
		}
	}

	private final void readAuthHeader() {
		byteBuffer.position(0);

		int receiveSize = ((int)(byteBuffer.getLong() & 0xFFFFFFFFFFFFL));

		if (receiveSize < 2 || receiveSize > byteBuffer.capacity()) {
			throw new AerospikeException.Parse("Invalid auth receive size: " + receiveSize);
		}
		byteBuffer.clear();
		byteBuffer.limit(receiveSize);
		state = AsyncCommand.AUTH_READ_BODY;
	}

	private final void readAuthBody() {
		int resultCode = byteBuffer.get(1) & 0xFF;

		if (resultCode != 0 && resultCode != ResultCode.SECURITY_NOT_ENABLED) {
			// Authentication failed. Session token probably expired.
			// Signal tend thread to perform node login, so future
			// transactions do not fail.
			node.signalLogin();

			// This is a rare event because the client tracks session
			// expiration and will relogin before session expiration.
			// Do not try to login on same socket because login can take
			// a long time and thousands of simultaneous logins could
			// overwhelm server.
			throw new AerospikeException(resultCode);
		}
	}

	private final void finish() {
		conn.unregister();
		conn.updateLastUsed();
		putByteBuffer();
		success();
	}

	private final void putByteBuffer() {
		if (byteBuffer != null) {
			eventLoop.putByteBuffer(byteBuffer);
			byteBuffer = null;
		}
	}

	@Override
	final boolean addConnection() {
		boolean ret = node.putAsyncConnection(conn, eventLoop.index);
		conn = null;
		return ret;
	}

	@Override
	final void closeConnection() {
		putByteBuffer();

		if (conn != null) {
			node.closeAsyncConnection(conn, eventLoop.index);
			conn = null;
		}
		else {
			node.decrAsyncConnection(eventLoop.index);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy