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

io.questdb.std.Rosti Maven / Gradle / Ivy

/*******************************************************************************
 *     ___                  _   ____  ____
 *    / _ \ _   _  ___  ___| |_|  _ \| __ )
 *   | | | | | | |/ _ \/ __| __| | | |  _ \
 *   | |_| | |_| |  __/\__ \ |_| |_| | |_) |
 *    \__\_\\__,_|\___||___/\__|____/|____/
 *
 *  Copyright (c) 2014-2019 Appsicle
 *  Copyright (c) 2019-2023 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.std;

import io.questdb.cairo.ColumnTypes;
import org.jetbrains.annotations.TestOnly;

import static io.questdb.std.Numbers.hexDigits;

public final class Rosti {

    public static long alloc(ColumnTypes types, long capacity) {
        // min capacity that works on all platforms is 16  
        assert capacity >= 16;

        final int columnCount = types.getColumnCount();
        final long mem = Unsafe.malloc(4L * columnCount, MemoryTag.NATIVE_ROSTI);
        try {
            long p = mem;
            for (int i = 0; i < columnCount; i++) {
                Unsafe.getUnsafe().putInt(p, types.getColumnType(i));
                p += Integer.BYTES;
            }
            // this is not an exact size of memory allocated for Rosti, but this is useful to
            // track that we free these maps
            long pRosti = alloc(mem, columnCount, Numbers.ceilPow2(capacity) - 1);
            if (pRosti != 0) {
                Unsafe.recordMemAlloc(getAllocMemory(pRosti), MemoryTag.NATIVE_ROSTI);
            }
            return pRosti;
        } finally {
            Unsafe.free(mem, 4L * columnCount, MemoryTag.NATIVE_ROSTI);
        }
    }

    public static native void clear(long pRosti);

    //turns on normal allocation inside rosti
    @TestOnly
    public static native void disableOOMOnMalloc();

    //triggers OOM on next allocation happening inside rosti
    @TestOnly
    public static native void enableOOMOnMalloc();

    public static void free(long pRosti) {
        long size = getAllocMemory(pRosti);
        free0(pRosti);
        Unsafe.recordMemAlloc(-size, MemoryTag.NATIVE_ROSTI);
    }

    public static native long getAllocMemory(long pRosti);

    public static long getCapacity(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + 3 * Long.BYTES);
    }

    public static long getCtrl(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti);
    }

    public static long getInitialValueSlot(long pRosti, int columnIndex) {
        return getInitialValuesSlot(pRosti) + Unsafe.getUnsafe().getInt(getValueOffsets(pRosti) + columnIndex * 4L);
    }

    public static long getInitialValuesSlot(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + 8 * Long.BYTES);
    }

    public static long getSize(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + 2 * Long.BYTES);
    }

    public static long getSlotShift(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + 5 * Long.BYTES);
    }

    public static long getSlotSize(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + 4 * Long.BYTES);
    }

    public static long getSlots(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + Long.BYTES);
    }

    public static long getValueOffsets(long pRosti) {
        return Unsafe.getUnsafe().getLong(pRosti + 7 * Long.BYTES);
    }

    //returns true if rosti is set to trigger OOM on  allocation
    @TestOnly
    public static native boolean isOOMOnMalloc();

    public static native boolean keyedHourCount(long pRosti, long pKeys, long count, int valueOffset);

    public static native boolean keyedHourCountDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourCountInt(long pRosti, long pKeys, long pInt, long count, int valueOffset);

    public static native boolean keyedHourCountLong(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    public static native boolean keyedHourDistinct(long pRosti, long pKeys, long count);

    public static native boolean keyedHourKSumDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourMaxDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourMaxInt(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourMaxLong(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourMinDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourMinInt(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourMinLong(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourNSumDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourSumDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourSumInt(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedHourSumLong(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    // sum long256
    public static native boolean keyedHourSumLong256(long pRosti, long pKeys, long pLong256, long count, int valueOffset);

    public static native boolean keyedHourSumLongLong(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    public static native boolean keyedIntAvgDoubleWrapUp(long pRosti, int valueOffset, double valueAtNull, long valueAtNullCount);

    public static native boolean keyedIntAvgLongLongWrapUp(long pRosti, int valueOffset, double valueAtNull, long valueAtNullCount);

    // avg long
    public static native boolean keyedIntAvgLongWrapUp(long pRosti, int valueOffset, double valueAtNull, long valueAtNullCount);

    public static native boolean keyedIntCount(long pRosti, long pKeys, long count, int valueOffset);

    public static native boolean keyedIntCountDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntCountInt(long pRosti, long pKeys, long pInt, long count, int valueOffset);

    public static native boolean keyedIntCountLong(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    public static native boolean keyedIntCountMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntCountWrapUp(long pRosti, int valueOffset, long valueAtNull);

    public static native boolean keyedIntDistinct(long pRosti, long pKeys, long count);

    // ksum double
    public static native boolean keyedIntKSumDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntKSumDoubleMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntKSumDoubleWrapUp(long pRosti, int valueOffset, double valueAtNull, long valueAtNullCount);

    // max double
    public static native boolean keyedIntMaxDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntMaxDoubleMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntMaxDoubleWrapUp(long pRosti, int valueOffset, double valueAtNull);

    // max int
    public static native boolean keyedIntMaxInt(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntMaxIntMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntMaxIntWrapUp(long pRosti, int valueOffset, int valueAtNull);

    // max long
    public static native boolean keyedIntMaxLong(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntMaxLongMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntMaxLongWrapUp(long pRosti, int valueOffset, long valueAtNull);

    // min double
    public static native boolean keyedIntMinDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntMinDoubleMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntMinDoubleWrapUp(long pRosti, int valueOffset, double valueAtNull);

    // min int
    public static native boolean keyedIntMinInt(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntMinIntMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntMinIntWrapUp(long pRosti, int valueOffset, int valueAtNull);

    // min long
    public static native boolean keyedIntMinLong(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntMinLongMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntMinLongWrapUp(long pRosti, int valueOffset, long valueAtNull);

    // nsum double
    public static native boolean keyedIntNSumDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntNSumDoubleMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntNSumDoubleWrapUp(long pRosti, int valueOffset, double valueAtNull, long valueAtNullCount, double valueAtNullC);

    // sum double
    public static native boolean keyedIntSumDouble(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntSumDoubleMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntSumDoubleWrapUp(long pRosti, int valueOffset, double valueAtNull, long valueAtNullCount);

    // sum int
    public static native boolean keyedIntSumInt(long pRosti, long pKeys, long pDouble, long count, int valueOffset);

    public static native boolean keyedIntSumIntMerge(long pRostiA, long pRostiB, int valueOffset);

    // sum long
    public static native boolean keyedIntSumLong(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    public static native boolean keyedIntSumLong256(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    public static native boolean keyedIntSumLong256Merge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntSumLong256WrapUp(long pRosti, int valueOffset, long v0, long v1, long v2, long v3, long valueAtNullCount);

    public static native boolean keyedIntSumLongLong(long pRosti, long pKeys, long pLong, long count, int valueOffset);

    public static native boolean keyedIntSumLongLongMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntSumLongLongWrapUp(long pRosti, int valueOffset, long valueAtNull, long valueAtNullCount);

    public static native boolean keyedIntSumLongMerge(long pRostiA, long pRostiB, int valueOffset);

    public static native boolean keyedIntSumLongWrapUp(long pRosti, int valueOffset, long valueAtNull, long valueAtNullCount);

    public static void printRosti(long pRosti) {
        final long slots = getSlots(pRosti);
        final long shift = getSlotShift(pRosti);
        long ctrl = getCtrl(pRosti);
        final long start = ctrl;
        long count = getSize(pRosti);
        System.out.println("size=" + count);
        System.out.println("capacity=" + getCapacity(pRosti));
        System.out.println("slot size=" + getSlotSize(pRosti));
        System.out.println("slot shift=" + getSlotShift(pRosti));
        System.out.print("initial slot=");
        long initialSlot = getInitialValuesSlot(pRosti);
        for (long i = 0, n = getSlotSize(pRosti); i < n; i++) {

            byte b = Unsafe.getUnsafe().getByte(initialSlot + i);
            final int v;
            if (b < 0) {
                v = 256 + b;
            } else {
                v = b;
            }

            if (v < 0x10) {
                System.out.print('0');
                System.out.print(hexDigits[b]);
            } else {
                System.out.print(hexDigits[v / 0x10]);
                System.out.print(hexDigits[v % 0x10]);
            }

            System.out.print(' ');
        }
        System.out.println();
        while (count > 0) {
            byte b = Unsafe.getUnsafe().getByte(ctrl);
            if ((b & 0x80) == 0) {
                long p = slots + ((ctrl - start) << shift);
                System.out.println(Unsafe.getUnsafe().getInt(p) + " -> " + Unsafe.getUnsafe().getDouble(p + 12));
                count--;
            }
            ctrl++;
        }
    }

    public static boolean reset(long pRosti, int size) {
        long oldSize = Rosti.getAllocMemory(pRosti);
        boolean success = reset0(pRosti, Numbers.ceilPow2(size) - 1);
        updateMemoryUsage(pRosti, oldSize);
        return success;
    }

    public static void updateMemoryUsage(long pRosti, long oldSize) {
        long newSize = Rosti.getAllocMemory(pRosti);
        Unsafe.recordMemAlloc(newSize - oldSize, MemoryTag.NATIVE_ROSTI);
    }

    private static native long alloc(long pKeyTypes, int keyTypeCount, long capacity);

    private static native void free0(long pRosti);

    //clears and shrinks to given size
    private static native boolean reset0(long pRosti, int size);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy