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

net.openhft.collections.SharedHashMapBuilder Maven / Gradle / Ivy

There is a newer version: 3.2.2
Show newest version
/*
 * Copyright 2013 Peter Lawrey
 *
 * 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 net.openhft.collections;

import net.openhft.lang.Maths;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

public class SharedHashMapBuilder implements Cloneable {

    static final int HEADER_SIZE = 128;
    static final int SEGMENT_HEADER = 64;
    private static final byte[] MAGIC = "SharedHM".getBytes();

    // used when configuring the number of segments.
    private int minSegments = 128;
    private int actualSegments = -1;
    // used when reading the number of entries per
    private int actualEntriesPerSegment = -1;

    private int entrySize = 256;
    private long entries = 1 << 20;
    private int replicas = 0;
    private boolean transactional = false;
    private long lockTimeOutMS = 1000;
    private int metaDataBytes = 0;
    private SharedMapEventListener eventListener = SharedMapEventListeners.NOP;
    private SharedMapErrorListener errorListener = SharedMapErrorListeners.LOGGING;
    private boolean putReturnsNull = false;
    private boolean removeReturnsNull = false;
    private boolean generatedKeyType = false;
    private boolean generatedValueType = false;


    @Override
    public SharedHashMapBuilder clone() {
        try {
            return (SharedHashMapBuilder) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError(e);
        }
    }

    /**
     * Set minimum number of segments.
     * 

* See concurrencyLevel in {@link java.util.concurrent.ConcurrentHashMap}. * * @return this builder object back */ public SharedHashMapBuilder minSegments(int minSegments) { this.minSegments = minSegments; return this; } public int minSegments() { return minSegments; } public SharedHashMapBuilder entrySize(int entrySize) { this.entrySize = entrySize; return this; } public int entrySize() { return entrySize; } public SharedHashMapBuilder entries(long entries) { this.entries = entries; return this; } public long entries() { return entries; } public SharedHashMapBuilder replicas(int replicas) { this.replicas = replicas; return this; } public int replicas() { return replicas; } public SharedHashMapBuilder actualEntriesPerSegment(int actualEntriesPerSegment) { this.actualEntriesPerSegment = actualEntriesPerSegment; return this; } public int actualEntriesPerSegment() { if (actualEntriesPerSegment > 0) return actualEntriesPerSegment; // round up to the next multiple of 64. int as = actualSegments(); int aeps = (int) (Math.max(1, entries * 2L / as) + 63) & ~63; return aeps; } public SharedHashMapBuilder actualSegments(int actualSegments) { this.actualSegments = actualSegments; return this; } public int actualSegments() { if (actualSegments > 0) return actualSegments; return (int) Maths.nextPower2(Math.max((entries >> 30) + 1, minSegments), 1); } /** * Not supported yet. */ public SharedHashMapBuilder transactional(boolean transactional) { this.transactional = transactional; return this; } public boolean transactional() { return transactional; } public SharedHashMap create(File file, Class kClass, Class vClass) throws IOException { SharedHashMapBuilder builder = clone(); for (int i = 0; i < 10; i++) { if (file.exists() && file.length() > 0) { readFile(file, builder); break; } if (file.createNewFile() || file.length() == 0) { newFile(file); break; } try { Thread.sleep(100); } catch (InterruptedException e) { throw new IOException(e); } } if (builder == null || !file.exists()) throw new FileNotFoundException("Unable to create " + file); return new VanillaSharedHashMap(builder, file, kClass, vClass); } private static void readFile(File file, SharedHashMapBuilder builder) throws IOException { ByteBuffer bb = ByteBuffer.allocateDirect(HEADER_SIZE).order(ByteOrder.nativeOrder()); FileInputStream fis = new FileInputStream(file); fis.getChannel().read(bb); fis.close(); bb.flip(); if (bb.remaining() < 22) throw new IOException("File too small, corrupted? " + file); byte[] bytes = new byte[8]; bb.get(bytes); if (!Arrays.equals(bytes, MAGIC)) throw new IOException("Unknown magic number, was " + new String(bytes, 0)); builder.actualSegments(bb.getInt()); builder.actualEntriesPerSegment(bb.getInt()); builder.entrySize(bb.getInt()); builder.replicas(bb.getInt()); builder.transactional(bb.get() == 'Y'); builder.metaDataBytes(bb.get() & 0xFF); if (builder.actualSegments() <= 0 || builder.actualEntriesPerSegment() <= 0 || builder.entrySize() <= 0) throw new IOException("Corrupt header for " + file); } private void newFile(File file) throws IOException { ByteBuffer bb = ByteBuffer.allocateDirect(HEADER_SIZE).order(ByteOrder.nativeOrder()); bb.put(MAGIC); bb.putInt(actualSegments()); bb.putInt(actualEntriesPerSegment()); bb.putInt(entrySize()); bb.putInt(replicas()); bb.put((byte) (transactional ? 'Y' : 'N')); bb.put((byte) metaDataBytes); bb.flip(); FileOutputStream fos = new FileOutputStream(file); fos.getChannel().write(bb); fos.close(); } public SharedHashMapBuilder lockTimeOutMS(long lockTimeOutMS) { this.lockTimeOutMS = lockTimeOutMS; return this; } public long lockTimeOutMS() { return lockTimeOutMS; } public SharedHashMapBuilder errorListener(SharedMapErrorListener errorListener) { this.errorListener = errorListener; return this; } public SharedMapErrorListener errorListener() { return errorListener; } /** * {@link this.put()} returns the previous value, functionality which is rarely used but fairly cheap for HashMap. * In the case, for an off heap collection, it has to create a new object (or return a recycled one) * Either way it's expensive for something you probably don't use. * * @param putReturnsNull false if you want {@link this.put()} to not return the object that was replaced but instead return null */ public SharedHashMapBuilder putReturnsNull(boolean putReturnsNull) { this.putReturnsNull = putReturnsNull; return this; } /** * {@link this.put()} returns the previous value, functionality which is rarely used but fairly cheap for HashMap. * In the case, for an off heap collection, it has to create a new object (or return a recycled one) * Either way it's expensive for something you probably don't use. * * @return true if {@link this.put()} is not going to return the object that was replaced but instead return null */ public boolean putReturnsNull() { return putReturnsNull; } /** * {@link this.remove()} returns the previous value, functionality which is rarely used but fairly cheap for HashMap. * In the case, for an off heap collection, it has to create a new object (or return a recycled one) * Either way it's expensive for something you probably don't use. * * @param removeReturnsNull false if you want {@link this.remove()} to not return the object that was removed but instead return null */ public SharedHashMapBuilder removeReturnsNull(boolean removeReturnsNull) { this.removeReturnsNull = removeReturnsNull; return this; } /** * {@link this.put()} returns the previous value, functionality which is rarely used but fairly cheap for HashMap. * In the case, for an off heap collection, it has to create a new object (or return a recycled one) * Either way it's expensive for something you probably don't use. * * @return true if {@link this.remove()} is not going to return the object that was removed but instead return null */ public boolean removeReturnsNull() { return removeReturnsNull; } public boolean generatedKeyType() { return generatedKeyType; } public SharedHashMapBuilder generatedKeyType(boolean generatedKeyType) { this.generatedKeyType = generatedKeyType; return this; } public boolean generatedValueType() { return generatedValueType; } public SharedHashMapBuilder generatedValueType(boolean generatedValueType) { this.generatedValueType = generatedValueType; return this; } public SharedHashMapBuilder metaDataBytes(int metaDataBytes) { if ((metaDataBytes & 0xFF) != metaDataBytes) throw new IllegalArgumentException("MetaDataBytes must be [0..255] was " + metaDataBytes); this.metaDataBytes = metaDataBytes; return this; } public int metaDataBytes() { return metaDataBytes; } public SharedHashMapBuilder eventListener(SharedMapEventListener eventListener) { this.eventListener = eventListener; return this; } public SharedMapEventListener eventListener() { return eventListener; } @Override public String toString() { return "SharedHashMapBuilder{" + "actualSegments=" + actualSegments() + ", minSegments=" + minSegments() + ", actualEntriesPerSegment=" + actualEntriesPerSegment() + ", entrySize=" + entrySize() + ", entries=" + entries() + ", replicas=" + replicas() + ", transactional=" + transactional() + ", lockTimeOutMS=" + lockTimeOutMS() + ", errorListener=" + errorListener() + ", putReturnsNull=" + putReturnsNull() + ", removeReturnsNull=" + removeReturnsNull() + ", generatedKeyType=" + generatedKeyType() + ", generatedValueType=" + generatedValueType() + ", metaDataBytes=" + metaDataBytes() + ", eventListener=" + eventListener() + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SharedHashMapBuilder that = (SharedHashMapBuilder) o; if (actualEntriesPerSegment() != that.actualEntriesPerSegment()) return false; if (actualSegments() != that.actualSegments()) return false; if (entries() != that.entries()) return false; if (entrySize() != that.entrySize()) return false; if (generatedKeyType() != that.generatedKeyType()) return false; if (generatedValueType() != that.generatedValueType()) return false; if (lockTimeOutMS() != that.lockTimeOutMS()) return false; if (minSegments() != that.minSegments()) return false; if (putReturnsNull() != that.putReturnsNull()) return false; if (removeReturnsNull() != that.removeReturnsNull()) return false; if (replicas() != that.replicas()) return false; if (transactional() != that.transactional()) return false; if (metaDataBytes() != that.metaDataBytes()) return false; return errorListener().equals(that.errorListener()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy