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

org.neo4j.coreedge.core.consensus.log.segmented.OpenEndRangeMap Maven / Gradle / Ivy

/*
 * Copyright (c) 2002-2016 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * Neo4j 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 this program. If not, see .
 */
package org.neo4j.coreedge.core.consensus.log.segmented;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;

/**
 * Keeps a map of sequential ranges to values, where the highest range is open (right-side unbounded).
 *
 * Typical example:
 * [ 0,  10] -> 1     (closed range)
 * [11, 300] -> 2     (closed range)
 * [301,   [ -> 3     (open range)
 *
 * An added range always replaces a part of existing ranges, which could either be only a part of
 * the open range or even the entire open range and parts of the closed ranges.
 *
 * @param  Type of keys which must be comparable.
 * @param  Type of values stored.
 */
class OpenEndRangeMap, V>
{
    static class ValueRange
    {
        private final K limit;
        private final V value;

        ValueRange( K limit, V value )
        {
            this.limit = limit;
            this.value = value;
        }

        Optional limit()
        {
            return Optional.ofNullable( limit );
        }

        Optional value()
        {
            return Optional.ofNullable( value );
        }

        @Override
        public boolean equals( Object o )
        {
            if ( this == o )
            { return true; }
            if ( o == null || getClass() != o.getClass() )
            { return false; }
            ValueRange that = (ValueRange) o;
            return Objects.equals( limit, that.limit ) &&
                   Objects.equals( value, that.value );
        }

        @Override
        public int hashCode()
        {
            return Objects.hash( limit, value );
        }
    }

    private final TreeMap tree = new TreeMap<>();

    /* We optimize by keeping the open end range directly accessible. */
    private K endKey = null;
    private V endValue = null;

    Collection replaceFrom( K from, V value )
    {
        Collection removed = new ArrayList<>();

        Iterator itr = tree.tailMap( from ).values().iterator();
        while ( itr.hasNext() )
        {
            removed.add( itr.next() );
            itr.remove();
        }

        tree.put( from, value );

        endKey = from;
        endValue = value;

        return removed;
    }

    ValueRange lookup( K at )
    {
        if ( endKey != null && endKey.compareTo( at ) <= 0 )
        {
            return new ValueRange<>( null, endValue );
        }

        Map.Entry entry = tree.floorEntry( at );
        return new ValueRange<>( tree.higherKey( at ), entry != null ? entry.getValue() : null );
    }

    public V last()
    {
        return endValue;
    }

    public Set> entrySet()
    {
        return tree.entrySet();
    }

    public Collection remove( K lessThan )
    {
        Collection removed = new ArrayList<>();
        K floor = tree.floorKey( lessThan );

        Iterator itr = tree.headMap( floor, false ).values().iterator();
        while ( itr.hasNext() )
        {
            removed.add( itr.next() );
            itr.remove();
        }

        if( tree.isEmpty() )
        {
            endKey = null;
            endValue = null;
        }

        return removed;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy