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

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

/*
 * 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.util.ArrayDeque;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import com.aerospike.client.AerospikeException;
import com.aerospike.client.cluster.Cluster;
import com.aerospike.client.cluster.Node;
import com.aerospike.client.command.Buffer;
import com.aerospike.client.command.Command;
import com.aerospike.client.metrics.LatencyType;
import com.aerospike.client.policy.Policy;

/**
 * Asynchronous command handler.
 */
public abstract class AsyncCommand extends Command {
	static final int MAX_BUFFER_SIZE = 1024 * 128;  // 128 KB
	static final int REGISTERED = 1;
	static final int DELAY_QUEUE = 2;
	static final int CHANNEL_INIT = 3;
	static final int CONNECT = 4;
	static final int TLS_HANDSHAKE = 5;
	static final int AUTH_WRITE = 6;
	static final int AUTH_READ_HEADER = 7;
	static final int AUTH_READ_BODY = 8;
	static final int COMMAND_WRITE = 9;
	static final int COMMAND_READ_HEADER = 10;
	static final int COMMAND_READ_BODY = 11;
	static final int COMPLETE = 12;

	Policy policy;
	ArrayDeque bufferQueue;
	int receiveSize;
	int commandSentCounter;
	final boolean isSingle;
	boolean compressed;
	boolean valid = true;

	/**
	 * Default constructor.
	 */
	public AsyncCommand(Policy policy, boolean isSingle) {
		super(policy.socketTimeout, policy.totalTimeout, policy.maxRetries);
		this.policy = policy;
		this.isSingle = isSingle;
	}

	/**
	 * Scan/Query constructor.
	 */
	public AsyncCommand(Policy policy, int socketTimeout, int totalTimeout) {
		super(socketTimeout, totalTimeout, 0);
		this.policy = policy;
		this.isSingle = false;
	}

	final int parseProto(long proto) {
		compressed = (((proto >> 48) & 0xFF) == Command.MSG_TYPE_COMPRESSED);
		receiveSize = (int)(proto & 0xFFFFFFFFFFFFL);
		return receiveSize;
	}

	final void initBuffer() {
		dataBuffer = getBuffer(8192);
	}

	@Override
	protected void sizeBuffer() {
		sizeBuffer(dataOffset);
	}

	void sizeBuffer(int size) {
		if (dataBuffer == null) {
			dataBuffer = getBuffer(size);
		}
		else {
			if (size > dataBuffer.length) {
				dataBuffer = resizeBuffer(dataBuffer, size);
			}
		}
	}

	void putBuffer() {
		if (dataBuffer != null) {
			putBuffer(dataBuffer);
			dataBuffer = null;
		}
	}

	protected byte[] getBuffer(int size) {
		if (size > MAX_BUFFER_SIZE) {
			// Allocate huge buffer, but do not put back in pool.
			return new byte[size];
		}

		byte[] buffer = bufferQueue.pollFirst();

		if (buffer == null || buffer.length < size) {
			// Round up to nearest 8KB.
			buffer = new byte[(size + 8191) & ~8191];
		}
		return buffer;
	}

	private byte[] resizeBuffer(byte[] buffer, int size) {
		if (size > MAX_BUFFER_SIZE) {
			// Put original buffer back in pool.
			putBuffer(buffer);
			// Allocate huge buffer, but do not put back in pool.
			return new byte[size];
		}
		// Round up to nearest 8KB.
		return new byte[(size + 8191) & ~8191];
	}

	protected void putBuffer(byte[] buffer) {
		if (buffer.length <= MAX_BUFFER_SIZE) {
			bufferQueue.addLast(buffer);
		}
	}

	final void validateHeaderSize() {
		if (receiveSize < Command.MSG_REMAINING_HEADER_SIZE) {
			throw new AerospikeException.Parse("Invalid receive size: " + receiveSize);
		}
	}

	boolean parseCommandResult() {
		if (compressed) {
			int usize = (int)Buffer.bytesToLong(dataBuffer, 0);
			byte[] buf = new byte[usize];

			Inflater inf = new Inflater();
			try {
				inf.setInput(dataBuffer, 8, receiveSize - 8);
				int rsize;

				try {
					rsize = inf.inflate(buf);
				}
				catch (DataFormatException dfe) {
					throw new AerospikeException.Serialize(dfe);
				}

				if (rsize != usize) {
					throw new AerospikeException("Decompressed size " + rsize + " is not expected " + usize);
				}

				dataBuffer = buf;
				dataOffset = 8;
				receiveSize = usize - 8;
			} finally {
				inf.end();
			}
		}
		else {
			dataOffset = 0;
		}
		return parseResult();
	}

	final void stop() {
		valid = false;
	}

	boolean retryBatch(Runnable command, long deadline) {
		// Override this method in batch to regenerate node assignments.
		return false;
	}

	boolean isWrite() {
		return false;
	}

	abstract Node getNode(Cluster cluster);
	abstract LatencyType getLatencyType();
	abstract void writeBuffer();
	abstract boolean parseResult();
	abstract boolean prepareRetry(boolean timeout);
	abstract void onSuccess();
	abstract void onFailure(AerospikeException ae);
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy