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

org.modeshape.jcr.query.BufferManager Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
/*
 * ModeShape (http://www.modeshape.org)
 *
 * 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 org.modeshape.jcr.query;

import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.mapdb.BTreeKeySerializer;
import org.mapdb.DB;
import org.mapdb.DB.BTreeMapMaker;
import org.mapdb.DB.HTreeSetMaker;
import org.mapdb.DBMaker;
import org.mapdb.HTreeMap;
import org.mapdb.Serializer;
import org.modeshape.common.collection.SingleIterator;
import org.modeshape.common.collection.Supplier;
import org.modeshape.jcr.ExecutionContext;
import org.modeshape.jcr.index.local.MapDB;
import org.modeshape.jcr.index.local.MapDB.ComparableUniqueKeyComparator;
import org.modeshape.jcr.index.local.MapDB.Serializers;
import org.modeshape.jcr.index.local.MapDB.UniqueKey;
import org.modeshape.jcr.index.local.MapDB.UniqueKeyComparator;
import org.modeshape.jcr.index.local.MapDB.UniqueKeyBTreeSerializer;
import org.modeshape.jcr.query.Tuples.TupleFactory;
import org.modeshape.jcr.query.model.TypeSystem.TypeFactory;
import org.modeshape.jcr.value.ValueFactories;

/**
 * A manager of temporary buffers used in the query system.
 * 
 * @author Randall Hauch ([email protected])
 */
public class BufferManager implements Serializers, AutoCloseable {

    /**
     * A basic buffer interface.
     * 
     * @author Randall Hauch ([email protected])
     */
    public static interface Buffer extends AutoCloseable {

        /**
         * Determine if this buffer is empty. This may be more efficient than {@link #size()}.
         * 
         * @return true if the buffer is empty, or false otherwise
         */
        boolean isEmpty();

        /**
         * Get the size of the buffer. This might be more expensive if the buffer is not created with the flag to keep the size.
         * 
         * @return the size of the buffer.
         */
        long size();

        /**
         * Close the buffer and release all resources. The buffer is not usable after this.
         */
        @Override
        void close();
    }

    /**
     * A buffer that maintains the insertion order of a series of values.
     * 
     * @param  the type of value
     * @author Randall Hauch ([email protected])
     */
    public static interface QueueBuffer extends Buffer, Iterable {

        /**
         * Add a value to the end of this buffer.
         * 
         * @param value the value to be added; may be null
         */
        void append( T value );

        /**
         * Get an iterator over all of the values.
         * 
         * @return the iterator; never null
         */
        @Override
        Iterator iterator();
    }

    public static interface Predicate {

        /**
         * Add the value to the buffer only if the buffer does not yet contain the value.
         *
         * @param value the value
         * @return true if the buffer has not yet seen that value, or false otherwise
         */
        boolean addIfAbsent( T value );
    }

    /**
     * A buffer used to determine distinct values.
     * 
     * @param  the type of the distinct value
     * @author Randall Hauch ([email protected])
     */
    public static interface DistinctBuffer extends Buffer, Iterable, Predicate {

        /**
         * Get an iterator over all of the records.
         * 
         * @return the iterator; never null
         */
        @Override
        Iterator iterator();
    }

    /**
     * A buffer used to sort values into ascending or descending order.
     * 
     * @param  the type of the sorting value
     * @param  the type of record that is to be sorted
     * @author Randall Hauch ([email protected])
     */
    public static interface SortingBuffer extends Buffer {
        /**
         * Put the supplied value into the buffer given its sortable value.
         * 
         * @param sortable the value of the record that is to be used for sorting
         * @param record the record
         */
        void put( SortType sortable,
                  RecordType record );

        /**
         * Get an iterator over all of the records in ascending order.
         * 
         * @return the ascending iterator
         */
        Iterator ascending();

        /**
         * Get an iterator over all of the records in descending order.
         * 
         * @return the ascending iterator
         */
        Iterator descending();

        /**
         * Get an iterator over all of the records that have the given sortable value.
         * 
         * @param key the sortable value
         * @return the iterator; null if there is no entry, or an iterator with one or more values
         */
        Iterator getAll( SortType key );

        /**
         * Get an iterator over all of the records that have a sortable value with in the specified range.
         * 
         * @param lowerKey the minimum sortable value; may be null if there is no minimum
         * @param includeLowerKey true if the values equal to or greater than {@code lowerKey} value is to be included, or false
         *        if only values greater than {@code lowerKey} should be included
         * @param upperKey the maximum sortable value; may be null if there is no maximum
         * @param includeUpperKey true if the values equal to or less than {@code upperKey} value are to be included, or false if
         *        only values less than {@code upperKey} should be included
         * @return the iterator; null if there is no entry, or an iterator with one or more values
         */
        Iterator getAll( SortType lowerKey,
                                     boolean includeLowerKey,
                                     SortType upperKey,
                                     boolean includeUpperKey );
    }

    /**
     * An object use to create a new {@link DistinctBuffer}.
     * 
     * @see BufferManager#createDistinctBuffer(Serializer)
     * @param  the type of value to be used in the buffer
     * @author Randall Hauch ([email protected])
     */
    public static interface QueueBufferMaker {
        /**
         * Specify whether to store the bufer on the heap.
         * 
         * @param useHeap true if the buffer's contents are to be stored on the heap, or false if off-heap storage should be used.
         * @return this maker instance; never null
         */
        QueueBufferMaker useHeap( boolean useHeap );

        /**
         * Create the {@link DistinctBuffer} instance.
         * 
         * @return the distinct buffer; never null
         */
        QueueBuffer make();
    }

    /**
     * An object use to create a new {@link DistinctBuffer}.
     * 
     * @see BufferManager#createDistinctBuffer(Serializer)
     * @param  the type of value to be used in the buffer
     * @author Randall Hauch ([email protected])
     */
    public static interface DistinctBufferMaker {
        /**
         * Specify whether to store the bufer on the heap.
         * 
         * @param useHeap true if the buffer's contents are to be stored on the heap, or false if off-heap storage should be used.
         * @return this maker instance; never null
         */
        DistinctBufferMaker useHeap( boolean useHeap );

        /**
         * Specify whether to keep track of the buffer size when adding value. Doing so may slow adds, but it will make returning
         * the size very quick. Adds may be faster if this is set to false, but asking the buffer for its size requires iterating
         * over the entire buffer and thus may be slower.
         * 
         * @param keepBufferSize true if the buffer is to efficiently track its size, or false if it can skip this and, only if
         *        {@link Buffer#size()} is called, compute the size in a brute force manner.
         * @return this maker instance; never null
         */
        DistinctBufferMaker keepSize( boolean keepBufferSize );

        /**
         * Create the {@link DistinctBuffer} instance.
         * 
         * @return the distinct buffer; never null
         */
        DistinctBuffer make();
    }

    /**
     * An object use to create a new {@link SortingBuffer}.
     * 
     * @see BufferManager#createSortingBuffer(BTreeKeySerializer, Serializer)
     * @param  the type of sortable value
     * @param  the type of record to be placed into the buffer
     * @author Randall Hauch ([email protected])
     */
    public static interface SortingBufferMaker {
        /**
         * Specify whether to store the bufer on the heap.
         * 
         * @param useHeap true if the buffer's contents are to be stored on the heap, or false if off-heap storage should be used.
         * @return this maker instance; never null
         */
        SortingBufferMaker useHeap( boolean useHeap );

        /**
         * Specify whether to keep track of the buffer size when adding value. Doing so may slow adds, but it will make returning
         * the size very quick. Adds may be faster if this is set to false, but asking the buffer for its size requires iterating
         * over the entire buffer and thus may be slower.
         * 
         * @param keepBufferSize true if the buffer is to efficiently track its size, or false if it can skip this and, only if
         *        {@link Buffer#size()} is called, compute the size in a brute force manner.
         * @return this maker instance; never null
         */
        SortingBufferMaker keepSize( boolean keepBufferSize );

        /**
         * Create the {@link SortingBuffer} instance.
         * 
         * @return the distinct buffer; never null
         */
        SortingBuffer make();
    }

    protected static final class DbHolder implements AutoCloseable {
        private final AtomicReference reference = new AtomicReference<>();
        private final Lock lock = new ReentrantLock();
        private final Supplier supplier;

        protected DbHolder( Supplier supplier ) {
            this.supplier = supplier;
        }

        public DB get() {
            DB db = reference.get();
            if (db == null) {
                try {
                    lock.lock();
                    // Allocate it ...
                    db = supplier.get();
                    reference.set(db);
                } finally {
                    lock.unlock();
                }
            }
            return db;
        }

        @Override
        public void close() {
            DB db = reference.getAndSet(null);
            if (db != null) {
                db.close();
            }
        }
    }

    private final static Supplier OFF_HEAP_DB_SUPPLIER = new Supplier() {
        @Override
        public DB get() {
            return DBMaker.newMemoryDirectDB().make();
        }
    };

    private final static Supplier ON_HEAP_DB_SUPPLIER = new Supplier() {
        @Override
        public DB get() {
            return DBMaker.newMemoryDB().make();
        }
    };

    private final Serializers serializers;
    private final DbHolder offheap;
    private final DbHolder onheap;
    private final AtomicLong dbCounter = new AtomicLong();

    public BufferManager( ExecutionContext context ) {
        this(context, OFF_HEAP_DB_SUPPLIER, ON_HEAP_DB_SUPPLIER);
    }

    protected BufferManager( ExecutionContext context,
                             Supplier offheapDbSupplier,
                             Supplier onheapDbSupplier ) {
        offheap = new DbHolder(offheapDbSupplier);
        onheap = new DbHolder(onheapDbSupplier);

        // Create the serializers ...
        ValueFactories factories = context.getValueFactories();
        serializers = MapDB.serializers(factories);
    }

    @Override
    public void close() {
        RuntimeException error = null;
        try {
            onheap.close();
        } catch (RuntimeException e) {
            error = e;
        } finally {
            try {
                offheap.close();
            } catch (RuntimeException e) {
                if (error == null) error = e;
            }
            if (error != null) throw error;
        }
    }

    /**
     * Obtain a maker object that can create a new {@link QueueBuffer}.
     * 
     * @param serializer the serializer for the value
     * @return the maker; never null
     */
    public  QueueBufferMaker createQueueBuffer( Serializer serializer ) {
        return new MakeOrderedBuffer("buffer-" + dbCounter.incrementAndGet(), serializer);
    }

    /**
     * Obtain a maker object that can create a new {@link DistinctBuffer}.
     * 
     * @param distinctSerializer the serializer for the distinct value
     * @return the maker; never null
     */
    public  DistinctBufferMaker createDistinctBuffer( Serializer distinctSerializer ) {
        return new MakeDistinctBuffer("buffer-" + dbCounter.incrementAndGet(), distinctSerializer);
    }

    /**
     * Obtain a maker object that can create a new {@link SortingBuffer} that will keep a single values for any given key.
     * 
     * @param keySerializer the serializer for the keys
     * @param valueSerializer the serializer for the values
     * @return the maker; never null
     */
    public  SortingBufferMaker createSortingBuffer( BTreeKeySerializer keySerializer,
                                                                Serializer valueSerializer ) {
        return new MakeSortingBuffer("buffer-" + dbCounter.incrementAndGet(), keySerializer, valueSerializer);
    }

    /**
     * Obtain a maker object that can create a new {@link SortingBuffer} that can store multiple values for any given key.
     * 
     * @param keySerializer the serializer for the keys
     * @param keyComparator the comparator for the keys, or null if natural ordering should be used
     * @param valueSerializer the serializer for the values
     * @return the maker; never null
     */
    public , V> SortingBufferMaker createSortingWithDuplicatesBuffer( Serializer keySerializer,
                                                                                                    Comparator keyComparator,
                                                                                                    Serializer valueSerializer ) {
        return new MakeSortingWithDuplicatesBuffer("buffer-" + dbCounter.incrementAndGet(), keySerializer, keyComparator,
                                                         valueSerializer);
    }

    @Override
    public Serializer serializerFor( Class type ) {
        return null;
    }

    @Override
    public BTreeKeySerializer bTreeKeySerializerFor( Class type,
                                                        Comparator comparator,
                                                        boolean pack ) {
        return null;
    }

    /**
     * Obtain a serializer for the given value type.
     * 
     * @param type the type; may not be null
     * @return the serializer
     */
    public Serializer serializerFor( TypeFactory type ) {
        if (type instanceof TupleFactory) {
            return ((TupleFactory)type).getSerializer(this);
        }
        return serializers.serializerFor(type.getType());
    }

    /**
     * Obtain a serializer for the given key type.
     * 
     * @param type the type; may not be null
     * @param pack true if the serializer can/should pack keys together when possible, or false otherwise
     * @return the serializer
     */
    public BTreeKeySerializer bTreeKeySerializerFor( TypeFactory type,
                                                        boolean pack ) {
        return serializers.bTreeKeySerializerFor(type.getType(), type.getComparator(), pack);
    }

    protected final DB db( boolean useHeap ) {
        return useHeap ? onheap.get() : offheap.get();
    }

    protected final void delete( String name,
                                 boolean onHeap ) {
        db(onHeap).delete(name);
    }

    protected abstract class CloseableBuffer implements Buffer {
        protected final String name;
        protected final boolean onHeap;

        protected CloseableBuffer( String name,
                                   boolean onHeap ) {
            this.name = name;
            this.onHeap = onHeap;
        }

        @Override
        public void close() {
            BufferManager.this.delete(name, onHeap);
        }
    }

    protected final class CloseableQueueBuffer extends CloseableBuffer implements QueueBuffer {
        protected final Map buffer;
        private final AtomicLong size = new AtomicLong();

        protected CloseableQueueBuffer( String name,
                                        boolean onHeap,
                                        Map buffer ) {
            super(name, onHeap);
            this.buffer = buffer;
        }

        @Override
        public boolean isEmpty() {
            return buffer.isEmpty();
        }

        @Override
        public long size() {
            return size.get();
        }

        @Override
        public void append( T value ) {
            buffer.put(size.getAndIncrement(), value);
        }

        @Override
        public Iterator iterator() {
            final AtomicLong counter = new AtomicLong(0L);
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return counter.get() < buffer.size();
                }

                @Override
                public T next() {
                    Long key = counter.getAndIncrement();
                    if (key.intValue() < buffer.size()) {
                        return buffer.get(key);
                    }
                    throw new NoSuchElementException();
                }

                @Override
                public void remove() {
                    throw new UnsupportedOperationException();
                }
            };
        }

        @Override
        public String toString() {
            return "QueueBuffer(" + name + ",size=" + size.get() + ")";
        }
    }

    protected final class CloseableDistinctBuffer extends CloseableBuffer implements DistinctBuffer {
        private final Set buffer;

        protected CloseableDistinctBuffer( String name,
                                           boolean onHeap,
                                           Set buffer ) {
            super(name, onHeap);
            this.buffer = buffer;
        }

        @Override
        public boolean isEmpty() {
            return buffer.isEmpty();
        }

        @Override
        public long size() {
            return buffer.size();
        }

        @Override
        public boolean addIfAbsent( T value ) {
            return buffer.add(value);
        }

        @Override
        public Iterator iterator() {
            return buffer.iterator();
        }

        @Override
        public String toString() {
            return "DistinctBuffer(" + name + ")";
        }
    }

    protected final class CloseableSortingBuffer extends CloseableBuffer implements SortingBuffer {
        private final NavigableMap buffer;

        protected CloseableSortingBuffer( String name,
                                          boolean onHeap,
                                          NavigableMap buffer ) {
            super(name, onHeap);
            this.buffer = buffer;
        }

        @Override
        public boolean isEmpty() {
            return buffer.isEmpty();
        }

        @Override
        public long size() {
            return buffer.size();
        }

        @Override
        public void put( K sortable,
                         V record ) {
            buffer.put(sortable, record);
        }

        @Override
        public Iterator getAll( K key ) {
            V value = buffer.get(key);
            return value == null ? null : new SingleIterator(value);
        }

        @Override
        public Iterator getAll( K lowerKey,
                                   boolean includeLowerKey,
                                   K upperKey,
                                   boolean includeUpperKey ) {
            if (lowerKey == null) {
                if (upperKey == null) {
                    // It is unbounded ...
                    return buffer.values().iterator();
                }
                return buffer.headMap(upperKey, includeUpperKey).values().iterator();
            }
            assert lowerKey != null;
            if (upperKey == null) {
                return buffer.tailMap(lowerKey, includeLowerKey).values().iterator();
            }
            return buffer.subMap(lowerKey, includeLowerKey, upperKey, includeUpperKey).values().iterator();
        }

        @Override
        public Iterator ascending() {
            final Iterator> entryIter = buffer.entrySet().iterator();
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return entryIter.hasNext();
                }

                @Override
                public V next() {
                    return entryIter.next().getValue();
                }

                @Override
                public void remove() {
                    entryIter.remove();
                }
            };
        }

        @Override
        public Iterator descending() {
            final Iterator> entryIter = buffer.descendingMap().entrySet().iterator();
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return entryIter.hasNext();
                }

                @Override
                public V next() {
                    return entryIter.next().getValue();
                }

                @Override
                public void remove() {
                    entryIter.remove();
                }
            };
        }

        @Override
        public String toString() {
            return "SortingBuffer(" + name + ")";
        }
    }

    protected final class CloseableSortingBufferWithDuplicates, V> extends CloseableBuffer
        implements SortingBuffer {
        private final NavigableMap, V> buffer;
        private final AtomicLong counter = new AtomicLong();

        protected CloseableSortingBufferWithDuplicates( String name,
                                                        boolean onHeap,
                                                        NavigableMap, V> buffer ) {
            super(name, onHeap);
            this.buffer = buffer;
        }

        @Override
        public boolean isEmpty() {
            return buffer.isEmpty();
        }

        @Override
        public long size() {
            return buffer.size();
        }

        @Override
        public void put( K sortable,
                         V record ) {
            buffer.put(new UniqueKey(sortable, counter.incrementAndGet()), record);
        }

        @Override
        public Iterator getAll( K key ) {
            UniqueKey lowest = new UniqueKey(key, 0);
            UniqueKey pastHighest = new UniqueKey(key, Long.MAX_VALUE);
            SortedMap, V> map = buffer.subMap(lowest, pastHighest);
            if (map == null || map.isEmpty()) return null;
            final Iterator, V>> entryIter = map.entrySet().iterator();
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return entryIter.hasNext();
                }

                @Override
                public V next() {
                    return entryIter.next().getValue();
                }

                @Override
                public void remove() {
                    entryIter.remove();
                }
            };
        }

        @Override
        public Iterator getAll( K lowerKey,
                                   boolean includeLowerKey,
                                   K upperKey,
                                   boolean includeUpperKey ) {
            UniqueKey lowest = includeLowerKey ? new UniqueKey(lowerKey, 0) : new UniqueKey(lowerKey, Long.MAX_VALUE);
            UniqueKey highest = includeUpperKey ? new UniqueKey(upperKey, Long.MAX_VALUE) : new UniqueKey(upperKey, 0L);
            if (upperKey == null) {
                if (lowerKey == null) return Collections.emptyList().iterator();
                return buffer.tailMap(lowest, includeLowerKey).values().iterator();
            } else if (lowerKey == null) {
                assert upperKey != null;
                return buffer.headMap(highest, includeUpperKey).values().iterator();
            }
            assert lowerKey != null;
            assert upperKey != null;
            return buffer.subMap(lowest, includeLowerKey, highest, includeUpperKey).values().iterator();
        }

        @Override
        public Iterator ascending() {
            final Iterator, V>> entryIter = buffer.entrySet().iterator();
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return entryIter.hasNext();
                }

                @Override
                public V next() {
                    return entryIter.next().getValue();
                }

                @Override
                public void remove() {
                    entryIter.remove();
                }
            };
        }

        @Override
        public Iterator descending() {
            final Iterator, V>> entryIter = buffer.descendingMap().entrySet().iterator();
            return new Iterator() {
                @Override
                public boolean hasNext() {
                    return entryIter.hasNext();
                }

                @Override
                public V next() {
                    return entryIter.next().getValue();
                }

                @Override
                public void remove() {
                    entryIter.remove();
                }
            };
        }

        @Override
        public String toString() {
            return "SortingBufferWithDuplicateKeys(" + name + ")";
        }
    }

    protected final class MakeOrderedBuffer implements QueueBufferMaker {
        private final String name;
        private boolean useHeap = true;
        private final Serializer serializer;

        protected MakeOrderedBuffer( String name,
                                     Serializer serializer ) {
            assert name != null;
            assert serializer != null;
            this.name = name;
            this.serializer = serializer;
        }

        @Override
        public MakeOrderedBuffer useHeap( boolean useHeap ) {
            this.useHeap = useHeap;
            return this;
        }

        @Override
        public QueueBuffer make() {
            HTreeMap values = db(useHeap).createHashMap(name).valueSerializer(serializer).counterEnable().make();
            return new CloseableQueueBuffer(name, useHeap, values);
        }
    }

    protected final class MakeDistinctBuffer implements DistinctBufferMaker {
        private final String name;
        private boolean useHeap = true;
        private boolean keepsize = false;
        private final Serializer serializer;

        protected MakeDistinctBuffer( String name,
                                      Serializer serializer ) {
            assert name != null;
            assert serializer != null;
            this.name = name;
            this.serializer = serializer;
        }

        @Override
        public DistinctBufferMaker keepSize( boolean keepBufferSize ) {
            this.keepsize = keepBufferSize;
            return this;
        }

        @Override
        public DistinctBufferMaker useHeap( boolean useHeap ) {
            this.useHeap = useHeap;
            return this;
        }

        @Override
        public DistinctBuffer make() {
            HTreeSetMaker maker = db(useHeap).createHashSet(name).serializer(serializer);
            if (keepsize) maker = maker.counterEnable();
            Set buffer = maker.make();
            return new CloseableDistinctBuffer(name, useHeap, buffer);
        }
    }

    protected final class MakeSortingBuffer implements SortingBufferMaker {
        private final String name;
        private boolean useHeap = true;
        private boolean keepsize = false;
        private final BTreeKeySerializer keySerializer;
        private final Serializer valueSerializer;

        protected MakeSortingBuffer( String name,
                                     BTreeKeySerializer keySerializer,
                                     Serializer valueSerializer ) {
            this.name = name;
            this.keySerializer = keySerializer;
            this.valueSerializer = valueSerializer;
        }

        @Override
        public SortingBufferMaker keepSize( boolean keepBufferSize ) {
            this.keepsize = keepBufferSize;
            return this;
        }

        @Override
        public SortingBufferMaker useHeap( boolean useHeap ) {
            this.useHeap = useHeap;
            return this;
        }

        @Override
        public SortingBuffer make() {
            BTreeMapMaker maker = db(useHeap).createTreeMap(name).keySerializer(keySerializer).valueSerializer(valueSerializer);
            if (keepsize) maker = maker.counterEnable();
            NavigableMap buffer = maker.make();
            return new CloseableSortingBuffer(name, useHeap, buffer);
        }
    }

    protected final class MakeSortingWithDuplicatesBuffer, V> implements SortingBufferMaker {
        private final String name;
        private boolean useHeap = true;
        private boolean keepsize = false;
        private final Serializer keySerializer;
        private final Serializer valueSerializer;
        private final Comparator keyComparator;

        @SuppressWarnings( "unchecked" )
        protected MakeSortingWithDuplicatesBuffer( String name,
                                                   Serializer keySerializer,
                                                   Comparator keyComparator,
                                                   Serializer valueSerializer ) {
            this.name = name;
            this.keySerializer = keySerializer;
            this.valueSerializer = valueSerializer;
            this.keyComparator = (Comparator)keyComparator;
        }

        @Override
        public SortingBufferMaker keepSize( boolean keepBufferSize ) {
            this.keepsize = keepBufferSize;
            return this;
        }

        @Override
        public SortingBufferMaker useHeap( boolean useHeap ) {
            this.useHeap = useHeap;
            return this;
        }

        @Override
        public SortingBuffer make() {
            Comparator> comparator = this.keyComparator != null ? new UniqueKeyComparator(keyComparator) : new ComparableUniqueKeyComparator();
            BTreeKeySerializer> uniqueKeySerializer = new UniqueKeyBTreeSerializer(keySerializer, comparator);
            BTreeMapMaker maker = db(useHeap).createTreeMap(name).keySerializer(uniqueKeySerializer)
                                             .valueSerializer(valueSerializer);
            if (keepsize) maker = maker.counterEnable();
            NavigableMap, V> buffer = maker.make();
            return new CloseableSortingBufferWithDuplicates(name, useHeap, buffer);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy