Package org.neo4j.collections.treemap

Source Code of org.neo4j.collections.treemap.BTreeMap

/**
* Copyright (c) 2002-2013 "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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.collections.treemap;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import org.neo4j.collections.btree.BTree;
import org.neo4j.collections.btree.KeyEntry;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.graphdb.Transaction;

/**
* A map implementation using {@link org.neo4j.index.impl.btree.BTree BTree}
* <p>
* Note: this implementation is not thread safe (yet).
* @param <K> The key type
* @param <V> The value type
*
* This class isn't ready for general usage yet and use of it is discouraged.
*
*/
public class BTreeMap<K,V> implements Map<K,V>
{
  static enum RelTypes implements RelationshipType
  {
    MAP_ENTRY,
  }
 
  private static final Object GOTO_NODE = Long.MIN_VALUE;
 
  private static final String MAP_NAME = "map_name";
  private static final String MAP_KEY = "map_key";
  private static final String MAP_VALUE = "map_value";
  // private static final String GOTO_NODE = "goto_node";
 
  private final Node underlyingNode;
  private BTree bTree;
  private String name;
  private GraphDatabaseService graphDb;
 
 
  /**
   * Creates/loads a persistent map based on a b-tree.
   * The {@code underlyingNode} can either be a new (just created) node
   * or a node that already represents a previously created map.
   *
   * @param name The unique name of the map or null if map already
   * created (using specified underlying node). The name must match the name
   * of the underlyingNode, otherwise an {@link IllegalArgumentException}
   * will be thrown.
   * @param underlyingNode The underlying node representing the map
   * @param graphDb The {@link GraphDatabaseService} instante.
   * @throws IllegalArgumentException if the underlying node is a map with
   * a different name set.
   */
  public BTreeMap( String name, Node underlyingNode,
      GraphDatabaseService graphDb )
  {
    if ( underlyingNode == null || graphDb == null )
    {
      throw new IllegalArgumentException(
        "Null parameter underlyingNode=" + underlyingNode +
        " graphDb=" + graphDb );
    }
    this.underlyingNode = underlyingNode;
    this.graphDb = graphDb;
    Transaction tx = graphDb.beginTx();
    try
    {
      if ( underlyingNode.hasProperty( MAP_NAME ) )
      {
        String storedName = (String) underlyingNode.getProperty(
          MAP_NAME );
        if ( name != null && !storedName.equals( name ) )
        {
          throw new IllegalArgumentException( "Name of map " +
            "for node=" + underlyingNode.getId() + "," +
            storedName + " is not same as passed in name=" +
            name );
        }
        if ( name == null )
        {
          this.name = (String) underlyingNode.getProperty(
            MAP_NAME );
        }
        else
        {
          this.name = name;
        }
      }
      else
      {
        underlyingNode.setProperty( MAP_NAME, name );
        this.name = name;
      }
      Relationship bTreeRel = underlyingNode.getSingleRelationship(
        BTree.RelTypes.TREE_ROOT,
        Direction.OUTGOING );
      if ( bTreeRel != null )
      {
        bTree = new BTree( graphDb, bTreeRel.getEndNode() );
      }
      else
      {
        Node bTreeNode = graphDb.createNode();
        underlyingNode.createRelationshipTo( bTreeNode,
          BTree.RelTypes.TREE_ROOT );
        bTree = new BTree( graphDb, bTreeNode );
      }
      tx.success();
    }
    finally
    {
      tx.finish();
    }
  }
 
  /**
   * Returns the name of this map, given at construction time.
   *
   * @return the name of this map.
   */
  public String getName()
  {
    return this.name;
  }
 
  Node getUnderlyingNode()
  {
    return underlyingNode;
  }
 
  /**
   * If key or value is {@code null} {@link IllegalArgumentException} is
   * thrown. Key and value must be valid neo4j properties.
   */
  public V put( K key, V value )
  {
    if ( key == null || value == null )
    {
      throw new IllegalArgumentException( "Null node" );
    }
    Transaction tx = graphDb.beginTx();
    try
    {
      int hashCode = key.hashCode();
      KeyEntry entry = bTree.addIfAbsent( hashCode, value );
      if ( entry != null )
      {
        entry.setKeyValue( key );
      }
      else
      {
        entry = bTree.getAsKeyEntry( hashCode );
        Object goOtherNode = entry.getKeyValue();
        Node bucketNode = null;
        if ( !goOtherNode.equals( GOTO_NODE ) )
        {
          Object prevValue = entry.getValue();
          Object prevKey = entry.getKeyValue();
          if ( prevKey.equals( key ) )
          {
            Object oldValue = entry.getValue();
            entry.setValue( value );
            tx.success();
            return (V) oldValue;
          }
          entry.setKeyValue( GOTO_NODE );
          bucketNode = graphDb.createNode();
          entry.setValue( bucketNode.getId() );
          Node prevEntry = graphDb.createNode();
          bucketNode.createRelationshipTo( prevEntry,
            RelTypes.MAP_ENTRY );
          prevEntry.setProperty( MAP_KEY, prevKey );
          prevEntry.setProperty( MAP_VALUE, prevValue );
          Node newEntry = graphDb.createNode();
          bucketNode.createRelationshipTo( newEntry,
            RelTypes.MAP_ENTRY );
          newEntry.setProperty( MAP_KEY, key );
          newEntry.setProperty( MAP_VALUE, value );
        }
        else
        {
          bucketNode = graphDb.getNodeById( (Long) entry.getValue() );
          for ( Relationship rel : bucketNode.getRelationships(
            RelTypes.MAP_ENTRY, Direction.OUTGOING ) )
          {
            Node entryNode = rel.getEndNode();
            if ( entryNode.getProperty( MAP_KEY ).equals( key ) )
            {
              entryNode.setProperty( MAP_VALUE, value );
              tx.success();
              return null;
            }
          }
          Node newEntry = graphDb.createNode();
          bucketNode.createRelationshipTo( newEntry,
            RelTypes.MAP_ENTRY );
          newEntry.setProperty( MAP_KEY, key );
          newEntry.setProperty( MAP_VALUE, value );
        }
      }
      tx.success();
      return null;
    }
    finally
    {
      tx.finish();
    }
  }
 
  public V remove( Object key )
  {
    Transaction tx = graphDb.beginTx();
    try
    {
      int hashCode = key.hashCode();
      KeyEntry entry = bTree.getAsKeyEntry( hashCode );
      if ( entry != null )
      {
        Object goOtherNode = entry.getKeyValue();
        if ( !goOtherNode.equals( GOTO_NODE ) )
        {
          if ( goOtherNode.equals( key ) )
          {
            Object value = entry.getValue();
            entry.remove();
            tx.success();
            return (V) value;
          }
        }
        else
        {
          Node bucketNode = graphDb.getNodeById(
            (Long) entry.getValue() );
          for ( Relationship rel : bucketNode.getRelationships(
            RelTypes.MAP_ENTRY, Direction.OUTGOING ) )
          {
            Node entryNode = rel.getEndNode();
            if ( entryNode.getProperty( MAP_KEY ).equals( key ) )
            {
              Object value = entryNode.getProperty( MAP_VALUE );
              rel.delete();
              entryNode.delete();
              tx.success();
              return (V) value;
            }
          }
        }
      }
      tx.success();
      return null;
    }
    finally
    {
      tx.finish();
    }
  }
 
  void validate()
  {
    bTree.validateTree();
  }
 
  public V get( Object key )
  {
    Transaction tx = graphDb.beginTx();
    try
    {
      int hashCode = key.hashCode();
      KeyEntry entry = bTree.getAsKeyEntry( hashCode );
      if ( entry != null )
      {
        Object goOtherNode = entry.getKeyValue();
        if ( !goOtherNode.equals( GOTO_NODE ) )
        {
          if ( goOtherNode.equals( key ) )
          {
            tx.success();
            return (V) entry.getValue();
          }
        }
        else
        {
          Node bucketNode = graphDb.getNodeById(
            (Long) entry.getValue() );
          for ( Relationship rel : bucketNode.getRelationships(
            RelTypes.MAP_ENTRY, Direction.OUTGOING ) )
          {
            Node entryNode = rel.getEndNode();
            if ( entryNode.getProperty( MAP_KEY ).equals( key ) )
            {
              tx.success();
              return (V) entryNode.getProperty( MAP_VALUE );
            }
          }
        }
      }
      tx.success();
      return null;
    }
    finally
    {
      tx.finish();
    }
  }
 
  public void clear()
  {
    deleteBuckets();
    bTree.delete();
    Node bTreeNode = graphDb.createNode();
    underlyingNode.createRelationshipTo( bTreeNode,
      BTree.RelTypes.TREE_ROOT );
    bTree = new BTree( graphDb, bTreeNode );
  }
 
  /**
   * Deletes this map and all its entries, even the underlyingNode.
   */
  public void delete()
  {
    deleteBuckets();
    bTree.delete();
    underlyingNode.delete();
  }

    private void deleteBuckets()
    {
        for ( KeyEntry entry : bTree.entries() )
    {
      Object goOtherNode = entry.getKeyValue();
      if ( goOtherNode.equals( GOTO_NODE ) )
      {
        Node bucketNode = graphDb.getNodeById(
          (Long) entry.getValue() );
        for ( Relationship rel : bucketNode.getRelationships(
          RelTypes.MAP_ENTRY, Direction.OUTGOING ) )
        {
          Node entryNode = rel.getEndNode();
          rel.delete();
          entryNode.delete();
        }
        bucketNode.delete();
      }
    }
    }

  /**
     * Deletes this map and all its entries, even the underlyingNode.
     *
   * @param commitInterval commits the transaction
   */
  public void delete( int commitInterval )
  {
    deleteBuckets();
    bTree.delete( commitInterval );
    underlyingNode.delete();
  }
 
  public Collection<V> values()
    {
      throw new UnsupportedOperationException();
    }

  public Set<K> keySet()
    {
      throw new UnsupportedOperationException();
    }

  public boolean containsKey( Object key )
    {
    throw new UnsupportedOperationException();
    }

  public boolean containsValue( Object value )
    {
    throw new UnsupportedOperationException();
    }

  public Set<java.util.Map.Entry<K, V>> entrySet()
    {
    throw new UnsupportedOperationException();
    }

  public boolean isEmpty()
    {
      // TODO Auto-generated method stub
    throw new UnsupportedOperationException();
    }

  public void putAll( Map<? extends K, ? extends V> t )
    {
    throw new UnsupportedOperationException();
    }

  public int size()
    {
    throw new UnsupportedOperationException();
    }
}
TOP

Related Classes of org.neo4j.collections.treemap.BTreeMap

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.