<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.voltdb.client;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.zip.InflaterOutputStream;

import org.apache.cassandra_voltpatches.MurmurHash3;
import org.voltcore.utils.Pair;
import org.voltdb.ParameterConverter;
import org.voltdb.VoltType;
import org.voltdb.VoltTypeException;
import org.voltdb.common.Constants;

import com.google_voltpatches.common.base.Preconditions;

/**
 * HashinatorLite is a read-only, simplifed version of the Hashinators that can be
 * used by the client without introducing lots of VoltDB dependencies.
 *
 * It currently has a bit more duplicated code than we'd like, but it's nice and
 * standalone.
 *
 */
public class HashinatorLite {

    public static enum HashinatorLiteType {
        LEGACY(0),
        ELASTIC(1);

        public final int typeId;

        private HashinatorLiteType(int typeId) {
            this.typeId = typeId;
        }
    };

    public static byte[] getLegacyConfigureBytes(int catalogPartitionCount) {
        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.putInt(catalogPartitionCount);
        return buf.array();
    }

    //Values for legacy
    private int catalogPartitionCount;

    //Values for Elastic
    /*
     * Pointer to an array of integers containing the tokens and partitions. Even values are tokens and odd values
     * are partition ids.
     */
    private long m_etokens;
    private int m_etokenCount;

    private final sun.misc.Unsafe unsafe;

    private sun.misc.Unsafe getUnsafe() {
        try {
            return sun.misc.Unsafe.getUnsafe();
        } catch (SecurityException se) {
            try {
                return java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
                    @Override
                    public sun.misc.Unsafe run() throws Exception {
                        java.lang.reflect.Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
                        f.setAccessible(true);
                        return (sun.misc.Unsafe) f.get(null);
                    }
                });
            } catch (java.security.PrivilegedActionException e) {
                throw new RuntimeException("Could not initialize intrinsics",
                        e.getCause());
            }
        }
    }

    private final HashinatorLiteType m_type;

    public HashinatorLiteType getType() {
        return m_type;
    }

    /**
     * Initialize TheHashinator with the specified implementation class and configuration.
     * The starting version number will be 0.
     */
    public HashinatorLite(HashinatorLiteType type, byte configBytes[], boolean cooked) {
        m_type = type;
        unsafe = getUnsafe();

        if (type == HashinatorLiteType.ELASTIC) {
            Pair<Long, Integer> p = (cooked ? updateCooked(configBytes) : updateRaw(configBytes));
            m_etokens = p.getFirst();
            m_etokenCount = p.getSecond();
        }
        else {
            catalogPartitionCount = ByteBuffer.wrap(configBytes).getInt();
        }
    }

    public HashinatorLite(int numPartitions) {
        this(HashinatorLiteType.LEGACY, getLegacyConfigureBytes(numPartitions), false);
    }

    /**
     * Update from optimized (cooked) wire format. token-1 token-2 ... partition-1 partition-2 ... tokens are 4 bytes
     *
     * @param compressedData optimized and compressed config data
     * @return token/partition map
     */
    private Pair<Long, Integer> updateCooked(byte[] compressedData) {
        // Uncompress (inflate) the bytes.
        byte[] cookedBytes;
        try {<commit_msg>ENG-5502: Add a finalize method to free unsafe memory to HashinatorLite.<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.voltdb.client;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.zip.InflaterOutputStream;

import org.apache.cassandra_voltpatches.MurmurHash3;
import org.voltcore.utils.Pair;
import org.voltdb.ParameterConverter;
import org.voltdb.VoltType;
import org.voltdb.VoltTypeException;
import org.voltdb.common.Constants;

import com.google_voltpatches.common.base.Preconditions;

/**
 * HashinatorLite is a read-only, simplifed version of the Hashinators that can be
 * used by the client without introducing lots of VoltDB dependencies.
 *
 * It currently has a bit more duplicated code than we'd like, but it's nice and
 * standalone.
 *
 */
public class HashinatorLite {

    public static enum HashinatorLiteType {
        LEGACY(0),
        ELASTIC(1);

        public final int typeId;

        private HashinatorLiteType(int typeId) {
            this.typeId = typeId;
        }
    };

    public static byte[] getLegacyConfigureBytes(int catalogPartitionCount) {
        ByteBuffer buf = ByteBuffer.allocate(4);
        buf.putInt(catalogPartitionCount);
        return buf.array();
    }

    //Values for legacy
    private int catalogPartitionCount;

    //Values for Elastic
    /*
     * Pointer to an array of integers containing the tokens and partitions. Even values are tokens and odd values
     * are partition ids.
     */
    private long m_etokens = 0;
    private int m_etokenCount;

    private final sun.misc.Unsafe unsafe;

    private sun.misc.Unsafe getUnsafe() {
        try {
            return sun.misc.Unsafe.getUnsafe();
        } catch (SecurityException se) {
            try {
                return java.security.AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
                    @Override
                    public sun.misc.Unsafe run() throws Exception {
                        java.lang.reflect.Field f = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
                        f.setAccessible(true);
                        return (sun.misc.Unsafe) f.get(null);
                    }
                });
            } catch (java.security.PrivilegedActionException e) {
                throw new RuntimeException("Could not initialize intrinsics",
                        e.getCause());
            }
        }
    }

    private final HashinatorLiteType m_type;

    public HashinatorLiteType getType() {
        return m_type;
    }

    /**
     * Initialize TheHashinator with the specified implementation class and configuration.
     * The starting version number will be 0.
     */
    public HashinatorLite(HashinatorLiteType type, byte configBytes[], boolean cooked) {
        m_type = type;
        unsafe = getUnsafe();

        if (type == HashinatorLiteType.ELASTIC) {
            Pair<Long, Integer> p = (cooked ? updateCooked(configBytes) : updateRaw(configBytes));
            m_etokens = p.getFirst();
            m_etokenCount = p.getSecond();
        }
        else {
            catalogPartitionCount = ByteBuffer.wrap(configBytes).getInt();
        }
    }

    public HashinatorLite(int numPartitions) {
        this(HashinatorLiteType.LEGACY, getLegacyConfigureBytes(numPartitions), false);
    }

    @Override
    public void finalize() {
        if (m_etokens != 0) {
            unsafe.freeMemory(m_etokens);
        }
    }

    /**
     * Update from optimized (cooked) wire format. token-1 token-2 ... partition-1 partition-2 ... tokens are 4 bytes
     *
     * @param compressedData optimized and compressed config data
     * @return token/partition map
     */
    private Pair<Long, Integer> updateCooked(byte[] compressedData) {
        // Uncompress (inflate) the bytes.
        byte[] cookedBytes;
        try {
{'fraction_non_alphanumeric': 0.08370718897034686, 'fraction_numerical': 0.004814531130320604, 'mean_word_length': 2.5262345679012346, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6882858', 'n_tokens_mistral': 2562, 'n_tokens_neox': 2454, 'n_words': 771}