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

com.sleepycat.je.tree.INTargetRep Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */
package com.sleepycat.je.tree;

import java.util.Arrays;

import com.sleepycat.je.dbi.MemoryBudget;
import com.sleepycat.je.evictor.Evictor;
import com.sleepycat.je.utilint.SizeofMarker;

/**
 * The abstract class that defines the various representations used to
 * represent an array of target pointers to children of an IN node. These
 * arrays can be sparse, so the non-default representations are designed to
 * make efficient representations for the sparse cases. Each specialized
 * representation is a subclass of INTargetReps.
 *
 * A new IN node starts out with the None representation and grows through a
 * sparse into the full default representation. Subsequently, the default
 * representation can be compacted into a Sparse or None representation
 * whenever an IN is stripped. Note that representations do not currently move
 * to more compact forms when entries are nulled to minimize the possibility of
 * tansitionary representation changes, since each representation change has
 * a cpu cost and a gc cost associated with it.
 */
public abstract class INTargetRep
    extends INArrayRep {

    /* Single instance used for None rep. */
    public static final None NONE = new None();

    /* Enumeration for the different types of supported representations. */
    public enum Type { DEFAULT, SPARSE, NONE }

    public INTargetRep() {
    }

    /* The default non-sparse representation. It simply wraps an array. */
    public static class Default extends INTargetRep {

        /* The target nodes */
        private final Node[] targets;

        public Default(int capacity) {
            this.targets = new Node[capacity];
        }

        /* Only for use by the Sizeof utility. */
        public Default(@SuppressWarnings("unused") SizeofMarker marker) {
            targets = null;
        }

        private Default(Node[] targets) {
            this.targets = targets;
        }

        @Override
        public Default resize(int capacity) {
            return new Default(Arrays.copyOfRange(targets, 0, capacity));
        }

        @Override
        public Type getType() {
            return Type.DEFAULT;
        }

        @Override
        public Node get(int idx) {
            return targets[idx];
        }

        @Override
        public INTargetRep set(int idx, Node node, IN parent) {
            targets[idx] = node;
            return this;
        }

        @Override
        public INTargetRep copy(int from, int to, int n, IN parent) {
            System.arraycopy(targets, from, targets, to, n);
            return this;
        }

        @Override
        public INTargetRep compact(IN parent) {
            int count = 0;
            for (Node target : targets) {
                if (target != null) {
                    count++;
                }
            }

            if ((count > Sparse.MAX_ENTRIES) ||
                (targets.length > Sparse.MAX_INDEX)) {
                return this;
            }

            INTargetRep newRep = null;
            if (count == 0) {
                newRep = NONE;
            } else {
                newRep = new Sparse(targets.length);
                for (int i=0; i < targets.length; i++) {
                    if (targets[i] != null) {
                        newRep.set(i, targets[i], parent);
                    }
                }
            }

            noteRepChange(newRep, parent);
            return newRep;
        }

        @Override
        public long calculateMemorySize() {
            return MemoryBudget.DEFAULT_TARGET_ENTRY_OVERHEAD +
                   MemoryBudget.objectArraySize(targets.length);
        }

        @Override
        public void updateCacheStats(@SuppressWarnings("unused")
                                     boolean increment,
                                     @SuppressWarnings("unused")
                                     Evictor evictor) {
            /* No stats for this default rep. */
        }
    }

    /**
     * Representation used when 1-4 children are cached. Note that the IN
     * itself may have more children, but they are not currently cached.
     * The INArrayRep is represented by two parallel arrays: an array of
     * indices (idxs) and an array of values (targets). All elements that are
     * not explicitly represented are null.
     */
    public static class Sparse extends INTargetRep {

        /* The maximum number of entries that can be represented. */
        public static final int MAX_ENTRIES = 4;

        /* The maximum index that can be represented. */
        public static final int MAX_INDEX = Short.MAX_VALUE;

        /*
         * The parallel arrays implementing the INArrayRep.
         */
        final short idxs[] = new short[MAX_ENTRIES];
        final Node targets[] = new Node[MAX_ENTRIES];

        public Sparse(int capacity) {

            /* Unroll initialization. */
            idxs[0] = idxs[1] = idxs[2] = idxs[3] = -1;
        }

        /* Only for use by the Sizeof utility. */
        public Sparse(@SuppressWarnings("unused") SizeofMarker marker) {
        }

        @Override
        public Sparse resize(int capacity) {
            return this;
        }

        @Override
        public Type getType() {
            return Type.SPARSE;
        }

        @Override
        public Node get(int j) {
            assert (j >= 0) && (j <= MAX_INDEX);

            /* Unrolled for loop */
            if (idxs[0] == j) {
                return targets[0];
            }
            if (idxs[1] == j) {
                return targets[1];
            }
            if (idxs[2] == j) {
                return targets[2];
            }
            if (idxs[3] == j) {
                return targets[3];
            }
            return null;
        }

        @Override
        public INTargetRep set(int j, Node node, IN parent) {

            assert (j >= 0) && (j <= MAX_INDEX);

            int slot = -1;
            for (int i=0; i < targets.length; i++) {

                if (idxs[i] == j) {
                    targets[i] = node;
                    return this;
                }

                if ((slot < 0) && (targets[i] == null)) {
                   slot = i;
                }
            }

            if (node == null) {
                return this;
            }

            /* Have a free slot, use it. */
            if (slot >= 0) {
                targets[slot] = node;
                idxs[slot] = (short)j;
                return this;
            }

            /* It's full, mutate it. */
            Default fe = new Default(parent.getMaxEntries());
            noteRepChange(fe, parent);

            for (int i=0; i < targets.length; i++) {
                if (targets[i] != null) {
                    fe.set(idxs[i], targets[i], parent);
                }
            }

            return fe.set(j, node, parent);
        }

        @Override
        public INTargetRep copy(int from, int to, int n, IN parent) {

            INTargetRep target = this;

            if ((to == from) || (n == 0)) {
                /* Nothing to do */
            } else if (to < from) {
                /* Copy ascending */
                for (int i = 0; i < n; i++) {
                    target = target.set(to++, get(from++), parent);
                }
            } else {
                /* to > from. Copy descending */
                from += n;
                to += n;
                for (int i = 0; i < n; i++) {
                    target = target.set(--to, get(--from), parent);
                }
            }
            return target;
        }

        @Override
        public INTargetRep compact(IN parent) {
            int count = 0;
            for (Node target : targets) {
                if (target != null) {
                    count++;
                }
            }
            if (count == 0) {
                None newRep = NONE;
                noteRepChange(newRep, parent);
                return newRep;
            }
            return this;
        }

        @Override
        public long calculateMemorySize() {
            /*
             * Note that fixed array sizes are already accounted for in the
             * SPARSE_TARGET_ENTRY_OVERHEAD computed vis Sizeof.
             */
            return MemoryBudget.SPARSE_TARGET_ENTRY_OVERHEAD;
        }

        @Override
        public void updateCacheStats(boolean increment, Evictor evictor) {
            if (increment) {
                evictor.getNINSparseTarget().incrementAndGet();
            } else {
                evictor.getNINSparseTarget().decrementAndGet();
            }
        }
    }

    /**
     * Representation used when an IN has no children cached.
     */
    public static class None extends INTargetRep {

        private None() {
        }

        /* Only for use by the Sizeof utility. */
        public None(@SuppressWarnings("unused") SizeofMarker marker) {
        }

        @Override
        public None resize(int capacity) {
            return this;
        }

        @Override
        public Type getType() {
            return Type.NONE;
        }

        @Override
        public Node get(@SuppressWarnings("unused") int idx) {
            return null;
        }

        @Override
        public INTargetRep set(int idx, Node node, IN parent) {

            if (node == null) {
                return this;
            }

            INTargetRep targets = new Sparse(parent.getMaxEntries());
            noteRepChange(targets, parent);
            return targets.set(idx, node, parent);
        }

        @Override
        public INTargetRep copy(@SuppressWarnings("unused") int from,
                                @SuppressWarnings("unused") int to,
                                @SuppressWarnings("unused") int n,
                                @SuppressWarnings("unused") IN parent) {
            /* Nothing to copy. */
            return this;
        }

        @Override
        public INTargetRep compact(IN parent) {
            return this;
        }

        @Override
        public long calculateMemorySize() {
            /* A single static instance is used. */
            return 0;
        }

        @Override
        public void updateCacheStats(boolean increment, Evictor evictor) {
            if (increment) {
                evictor.getNINNoTarget().incrementAndGet();
            } else {
                evictor.getNINNoTarget().decrementAndGet();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy