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

io.deephaven.engine.table.impl.NaturalJoinModifiedSlotTracker Maven / Gradle / Ivy

There is a newer version: 0.37.1
Show newest version
/**
 * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
 */
package io.deephaven.engine.table.impl;

import io.deephaven.engine.table.impl.sources.LongArraySource;

/**
 * A tracker for modified join hash table slots.
 *
 * After adding an entry, you get back a cookie, which must be passed in on future modification operations for that
 * slot.
 *
 * To process the entries after modifications are complete, call {@link #forAllModifiedSlots(ModifiedSlotConsumer)}.
 */
public class NaturalJoinModifiedSlotTracker {
    private static final int CHUNK_SIZE = 4096;
    private final LongArraySource modifiedSlots = new LongArraySource();
    /** the original right values, parallel to modifiedSlots. */
    private final LongArraySource originalRightValues = new LongArraySource();
    /**
     * the location that we must write to in modified slots; also if we have a pointer that falls outside the range [0,
     * pointer); then we know it is invalid
     */
    private long pointer;
    /** how many slots we have allocated */
    private long allocated;
    /** Each time we clear, we add an offset to our cookies, this prevents us from reading old values */
    private long cookieGeneration;

    private static final int FLAG_SHIFT = 16;
    public static final int FLAG_MASK = 0xF;
    public static final byte FLAG_RIGHT_SHIFT = 0x1;
    public static final byte FLAG_RIGHT_MODIFY_PROBE = 0x2;
    public static final byte FLAG_RIGHT_CHANGE = 0x4;
    public static final byte FLAG_RIGHT_ADD = 0x8;

    /**
     * Remove all entries from the tracker.
     */
    void clear() {
        cookieGeneration += pointer;
        if (cookieGeneration > Long.MAX_VALUE / 2) {
            cookieGeneration = 0;
        }
        pointer = 0;
    }

    /**
     * Is this cookie within our valid range (greater than or equal to our generation, but less than the pointer after
     * adjustment?
     *
     * @param cookie the cookie to check for validity
     *
     * @return true if the cookie is from the current generation, and references a valid slot in our table
     */
    private boolean isValidCookie(long cookie) {
        return cookie >= cookieGeneration && getPointerFromCookie(cookie) < pointer;
    }

    /**
     * Get a cookie to return to the user, given a pointer value.
     *
     * @param pointer the pointer to convert to a cookie
     * @return the cookie to return to the user
     */
    private long getCookieFromPointer(long pointer) {
        return cookieGeneration + pointer;
    }

    /**
     * Given a valid user's cookie, return the corresponding pointer.
     *
     * @param cookie the valid cookie
     * @return the pointer into modifiedSlots
     */
    private long getPointerFromCookie(long cookie) {
        return cookie - cookieGeneration;
    }

    /**
     * Add a slot in the main table.
     *
     * @param slot the slot to add.
     * @param originalRightValue if we are the addition of the slot, what the right value was before our modification
     *        (otherwise ignored)
     * @param flags the flags to or into our state
     *
     * @return the cookie for future access
     */
    public long addMain(final long cookie, final int slot, final long originalRightValue, byte flags) {
        if (originalRightValue < 0) {
            flags |= FLAG_RIGHT_ADD;
        }
        if (!isValidCookie(cookie)) {
            return doAddition(slot, originalRightValue, flags);
        } else {
            return updateFlags(cookie, flags);
        }
    }


    private long doAddition(final int slot, final long originalRightValue, byte flags) {
        if (pointer == allocated) {
            allocated += CHUNK_SIZE;
            modifiedSlots.ensureCapacity(allocated);
            originalRightValues.ensureCapacity(allocated);
        }
        modifiedSlots.set(pointer, ((long) slot << FLAG_SHIFT) | flags);
        originalRightValues.set(pointer, originalRightValue);
        return getCookieFromPointer(pointer++);
    }

    private long updateFlags(final long cookie, byte flags) {
        final long pointer = getPointerFromCookie(cookie);
        final long existingValue = modifiedSlots.getLong(pointer);
        modifiedSlots.set(pointer, existingValue | flags);
        return cookie;
    }

    /**
     * For each main and overflow value, call slotConsumer.
     *
     * @param slotConsumer the consumer of our values
     */
    void forAllModifiedSlots(ModifiedSlotConsumer slotConsumer) {
        for (int ii = 0; ii < pointer; ++ii) {
            final long slotAndFlag = modifiedSlots.getLong(ii);
            final int slot = (int) (slotAndFlag >> FLAG_SHIFT);
            final byte flag = (byte) (slotAndFlag & FLAG_MASK);
            slotConsumer.accept(slot, originalRightValues.getLong(ii), flag);
        }
    }

    /**
     * Move a main table location.
     *
     * @param oldTableLocation the old hash slot
     * @param newTableLocation the new hash slot
     */
    public void moveTableLocation(long cookie, @SuppressWarnings("unused") int oldTableLocation,
            int newTableLocation) {
        if (isValidCookie(cookie)) {
            final long pointer = getPointerFromCookie(cookie);
            final long existingSlotAndFlag = modifiedSlots.getLong(pointer);
            final byte flag = (byte) (existingSlotAndFlag & FLAG_MASK);
            final long newSlotAndFlag = ((long) newTableLocation << FLAG_SHIFT) | flag;
            modifiedSlots.set(pointer, newSlotAndFlag);
        }
    }

    /**
     * Move a location from overflow to the main table.
     *
     * @param overflowLocation the old overflow location
     * @param tableLocation the new table location
     */
    void promoteFromOverflow(long cookie, @SuppressWarnings("unused") int overflowLocation, int tableLocation) {
        if (isValidCookie(cookie)) {
            final long pointer = getPointerFromCookie(cookie);
            final long existingSlotAndFlag = modifiedSlots.getLong(pointer);
            final byte flag = (byte) (existingSlotAndFlag & FLAG_MASK);
            final long newSlotAndFlag = ((long) tableLocation << FLAG_SHIFT) | flag;
            modifiedSlots.set(pointer, newSlotAndFlag);
        }
    }

    interface ModifiedSlotConsumer {
        void accept(int slot, long originalRightValue, byte flag);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy