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

org.apache.activemq.artemis.utils.AbstractByteBufPool Maven / Gradle / Ivy

There is a newer version: 2.36.0
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.activemq.artemis.utils;

import org.apache.activemq.artemis.shaded.io.netty.buffer.ByteBuf;
import org.apache.activemq.artemis.shaded.io.netty.util.internal.MathUtil;
import org.apache.activemq.artemis.shaded.io.netty.util.internal.PlatformDependent;

/**
 * Thread-safe {@code } interner.
 * 

* Differently from {@link String#intern()} it contains a fixed amount of entries and * when used by concurrent threads it doesn't ensure the uniqueness of the entries ie * the same entry could be allocated multiple times by concurrent calls. */ public abstract class AbstractByteBufPool { public static final int DEFAULT_POOL_CAPACITY = 32; private final T[] entries; private final int mask; private final int shift; public AbstractByteBufPool() { this(DEFAULT_POOL_CAPACITY); } public AbstractByteBufPool(final int capacity) { entries = (T[]) new Object[MathUtil.findNextPositivePowerOfTwo(capacity)]; mask = entries.length - 1; //log2 of entries.length shift = 31 - Integer.numberOfLeadingZeros(entries.length); } /** * Batch hash code implementation that works at its best if {@code bytes} * contains a {@link org.apache.activemq.artemis.api.core.SimpleString} encoded. */ private static int hashCode(final ByteBuf bytes, final int offset, final int length) { if (PlatformDependent.isUnaligned() && PlatformDependent.hasUnsafe()) { //if the platform allows it, the hash code could be computed without bounds checking if (bytes.hasArray()) { return onHeapHashCode(bytes.array(), bytes.arrayOffset() + offset, length); } else if (bytes.hasMemoryAddress()) { return offHeapHashCode(bytes.memoryAddress(), offset, length); } } return byteBufHashCode(bytes, offset, length); } private static int onHeapHashCode(final byte[] bytes, final int offset, final int length) { final int intCount = length >>> 1; final int byteCount = length & 1; int hashCode = 1; int arrayIndex = offset; for (int i = 0; i < intCount; i++) { hashCode = 31 * hashCode + PlatformDependent.getShort(bytes, arrayIndex); arrayIndex += 2; } for (int i = 0; i < byteCount; i++) { hashCode = 31 * hashCode + PlatformDependent.getByte(bytes, arrayIndex++); } return hashCode; } private static int offHeapHashCode(final long address, final int offset, final int length) { final int intCount = length >>> 1; final int byteCount = length & 1; int hashCode = 1; int arrayIndex = offset; for (int i = 0; i < intCount; i++) { hashCode = 31 * hashCode + PlatformDependent.getShort(address + arrayIndex); arrayIndex += 2; } for (int i = 0; i < byteCount; i++) { hashCode = 31 * hashCode + PlatformDependent.getByte(address + arrayIndex++); } return hashCode; } private static int byteBufHashCode(final ByteBuf byteBuf, final int offset, final int length) { final int intCount = length >>> 1; final int byteCount = length & 1; int hashCode = 1; int arrayIndex = offset; for (int i = 0; i < intCount; i++) { final short shortLE = byteBuf.getShortLE(arrayIndex); final short nativeShort = PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(shortLE) : shortLE; hashCode = 31 * hashCode + nativeShort; arrayIndex += 2; } for (int i = 0; i < byteCount; i++) { hashCode = 31 * hashCode + byteBuf.getByte(arrayIndex++); } return hashCode; } /** * Returns {@code true} if {@code length}'s {@code byteBuf} content from {@link ByteBuf#readerIndex()} can be pooled, * {@code false} otherwise. */ protected abstract boolean canPool(ByteBuf byteBuf, int length); /** * Create a new entry. */ protected abstract T create(ByteBuf byteBuf, int length); /** * Returns {@code true} if the {@code entry} content is the same of {@code byteBuf} at the specified {@code offset} * and {@code length} {@code false} otherwise. */ protected abstract boolean isEqual(T entry, ByteBuf byteBuf, int offset, int length); /** * Returns a pooled entry if possible, a new one otherwise. *

* The {@code byteBuf}'s {@link ByteBuf#readerIndex()} is incremented by {@code length} after it. */ public final T getOrCreate(final ByteBuf byteBuf) { final int length = byteBuf.readInt(); if (!canPool(byteBuf, length)) { return create(byteBuf, length); } else { if (!byteBuf.isReadable(length)) { throw new IndexOutOfBoundsException(); } final int bytesOffset = byteBuf.readerIndex(); final int hashCode = hashCode(byteBuf, bytesOffset, length); //fast % operation with power of 2 entries.length final int firstIndex = hashCode & mask; final T firstEntry = entries[firstIndex]; if (isEqual(firstEntry, byteBuf, bytesOffset, length)) { byteBuf.skipBytes(length); return firstEntry; } final int secondIndex = (hashCode >> shift) & mask; final T secondEntry = entries[secondIndex]; if (isEqual(secondEntry, byteBuf, bytesOffset, length)) { byteBuf.skipBytes(length); return secondEntry; } final T internedEntry = create(byteBuf, length); final int entryIndex = firstEntry == null ? firstIndex : secondIndex; entries[entryIndex] = internedEntry; return internedEntry; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy