Package com.orientechnologies.orient.core.index.engine

Source Code of com.orientechnologies.orient.core.index.engine.OHashTableIndexEngine

/*
  *
  *  *  Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com)
  *  *
  *  *  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.
  *  *
  *  * For more information: http://www.orientechnologies.com
  *
  */
package com.orientechnologies.orient.core.index.engine;

import com.orientechnologies.common.serialization.types.OBinarySerializer;
import com.orientechnologies.orient.core.config.OGlobalConfiguration;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.record.ODatabaseRecord;
import com.orientechnologies.orient.core.db.record.ODatabaseRecordInternal;
import com.orientechnologies.orient.core.db.record.OIdentifiable;
import com.orientechnologies.orient.core.id.ORID;
import com.orientechnologies.orient.core.index.OIndexAbstractCursor;
import com.orientechnologies.orient.core.index.OIndexCursor;
import com.orientechnologies.orient.core.index.OIndexDefinition;
import com.orientechnologies.orient.core.index.OIndexEngine;
import com.orientechnologies.orient.core.index.OIndexKeyCursor;
import com.orientechnologies.orient.core.index.ORuntimeKeyIndexDefinition;
import com.orientechnologies.orient.core.index.hashindex.local.OHashIndexBucket;
import com.orientechnologies.orient.core.index.hashindex.local.OLocalHashTable;
import com.orientechnologies.orient.core.index.hashindex.local.OMurmurHash3HashFunction;
import com.orientechnologies.orient.core.iterator.OEmptyIterator;
import com.orientechnologies.orient.core.record.impl.ORecordBytes;
import com.orientechnologies.orient.core.serialization.serializer.binary.OBinarySerializerFactory;
import com.orientechnologies.orient.core.serialization.serializer.binary.impl.index.OCompositeKeySerializer;
import com.orientechnologies.orient.core.serialization.serializer.binary.impl.index.OSimpleKeySerializer;
import com.orientechnologies.orient.core.serialization.serializer.stream.OStreamSerializer;
import com.orientechnologies.orient.core.storage.impl.local.OAbstractPaginatedStorage;
import com.orientechnologies.orient.core.storage.impl.local.paginated.base.ODurablePage;

import java.util.Collections;
import java.util.Iterator;
import java.util.Map;

/**
* @author Andrey Lomakin
* @since 15.07.13
*/
public final class OHashTableIndexEngine<V> implements OIndexEngine<V> {
  public static final String                     METADATA_FILE_EXTENSION    = ".him";
  public static final String                     TREE_FILE_EXTENSION        = ".hit";
  public static final String                     BUCKET_FILE_EXTENSION      = ".hib";
  public static final String                     NULL_BUCKET_FILE_EXTENSION = ".hnb";

  private final OLocalHashTable<Object, V>       hashTable;
  private final OMurmurHash3HashFunction<Object> hashFunction;

  private volatile ORID                          identity;

  public OHashTableIndexEngine(Boolean durableInNonTxMode, ODurablePage.TrackMode trackMode) {
    hashFunction = new OMurmurHash3HashFunction<Object>();

    boolean durableInNonTx;
    if (durableInNonTxMode == null)
      durableInNonTx = OGlobalConfiguration.INDEX_DURABLE_IN_NON_TX_MODE.getValueAsBoolean();
    else
      durableInNonTx = durableInNonTxMode;

    hashTable = new OLocalHashTable<Object, V>(METADATA_FILE_EXTENSION, TREE_FILE_EXTENSION, BUCKET_FILE_EXTENSION,
        NULL_BUCKET_FILE_EXTENSION, hashFunction, durableInNonTx, trackMode);
  }

  @Override
  public void init() {
  }

  @Override
  public void create(String indexName, OIndexDefinition indexDefinition, String clusterIndexName,
      OStreamSerializer valueSerializer, boolean isAutomatic) {
    OBinarySerializer keySerializer;

    if (indexDefinition != null) {
      if (indexDefinition instanceof ORuntimeKeyIndexDefinition) {
        keySerializer = ((ORuntimeKeyIndexDefinition) indexDefinition).getSerializer();
      } else {
        if (indexDefinition.getTypes().length > 1) {
          keySerializer = OCompositeKeySerializer.INSTANCE;
        } else {
          keySerializer = OBinarySerializerFactory.getInstance().getObjectSerializer(indexDefinition.getTypes()[0]);
        }
      }
    } else
      keySerializer = new OSimpleKeySerializer();

    final ODatabaseRecordInternal database = getDatabase();
    final ORecordBytes identityRecord = new ORecordBytes();
    final OAbstractPaginatedStorage storageLocalAbstract = (OAbstractPaginatedStorage) database.getStorage();

    database.save(identityRecord, clusterIndexName);
    identity = identityRecord.getIdentity();

    hashFunction.setValueSerializer(keySerializer);
    hashTable.create(indexName, keySerializer, (OBinarySerializer<V>) valueSerializer,
        indexDefinition != null ? indexDefinition.getTypes() : null, storageLocalAbstract, indexDefinition != null
            && !indexDefinition.isNullValuesIgnored());
  }

  @Override
  public void flush() {
    hashTable.flush();
  }

  @Override
  public void deleteWithoutLoad(String indexName) {
    hashTable.deleteWithoutLoad(indexName, (OAbstractPaginatedStorage) getDatabase().getStorage().getUnderlying());
  }

  @Override
  public void delete() {
    hashTable.delete();
  }

  @Override
  public void load(ORID indexRid, String indexName, OIndexDefinition indexDefinition, OStreamSerializer valueSerializer,
      boolean isAutomatic) {
    identity = indexRid;
    hashTable.load(indexName, indexDefinition != null ? indexDefinition.getTypes() : null,
        (OAbstractPaginatedStorage) getDatabase().getStorage().getUnderlying(),
        indexDefinition != null && !indexDefinition.isNullValuesIgnored());
    hashFunction.setValueSerializer(hashTable.getKeySerializer());
  }

  @Override
  public boolean contains(Object key) {
    return hashTable.get(key) != null;
  }

  @Override
  public boolean remove(Object key) {
    return hashTable.remove(key) != null;
  }

  @Override
  public void clear() {
    hashTable.clear();
  }

  @Override
  public void close() {
    hashTable.close();
  }

  @Override
  public V get(Object key) {
    return hashTable.get(key);
  }

  @Override
  public void put(Object key, V value) {
    hashTable.put(key, value);
  }

  @Override
  public long size(ValuesTransformer<V> transformer) {
    if (transformer == null)
      return hashTable.size();
    else {
      OHashIndexBucket.Entry<Object, V> firstEntry = hashTable.firstEntry();
      if (firstEntry == null)
        return 0;

      OHashIndexBucket.Entry<Object, V>[] entries = hashTable.ceilingEntries(firstEntry.key);
      long counter = 0;

      while (entries.length > 0) {
        for (OHashIndexBucket.Entry<Object, V> entry : entries)
          counter += transformer.transformFromValue(entry.value).size();

        entries = hashTable.higherEntries(entries[entries.length - 1].key);
      }

      return counter;
    }
  }

  @Override
  public ORID getIdentity() {
    return identity;
  }

  @Override
  public boolean hasRangeQuerySupport() {
    return false;
  }

  @Override
  public OIndexCursor iterateEntriesBetween(Object rangeFrom, boolean fromInclusive, Object rangeTo, boolean toInclusive,
      boolean ascSortOrder, ValuesTransformer<V> transformer) {
    throw new UnsupportedOperationException("iterateEntriesBetween");
  }

  @Override
  public OIndexCursor iterateEntriesMajor(Object fromKey, boolean isInclusive, boolean ascSortOrder,
      ValuesTransformer<V> transformer) {
    throw new UnsupportedOperationException("iterateEntriesMajor");
  }

  @Override
  public OIndexCursor iterateEntriesMinor(Object toKey, boolean isInclusive, boolean ascSortOrder, ValuesTransformer<V> transformer) {
    throw new UnsupportedOperationException("iterateEntriesMinor");
  }

  @Override
  public Object getFirstKey() {
    throw new UnsupportedOperationException("firstKey");
  }

  @Override
  public Object getLastKey() {
    throw new UnsupportedOperationException("lastKey");
  }

  @Override
  public OIndexCursor cursor(final ValuesTransformer<V> valuesTransformer) {
    return new OIndexAbstractCursor() {
      private int                                 nextEntriesIndex;
      private OHashIndexBucket.Entry<Object, V>[] entries;

      private Iterator<OIdentifiable>             currentIterator = new OEmptyIterator<OIdentifiable>();
      private Object                              currentKey;

      {
        OHashIndexBucket.Entry<Object, V> firstEntry = hashTable.firstEntry();
        if (firstEntry == null)
          entries = new OHashIndexBucket.Entry[0];
        else
          entries = hashTable.ceilingEntries(firstEntry.key);

        if (entries.length == 0)
          currentIterator = null;
      }

      @Override
      public Map.Entry<Object, OIdentifiable> nextEntry() {
        if (currentIterator == null)
          return null;

        if (currentIterator.hasNext())
          return nextCursorValue();

        while (currentIterator != null && !currentIterator.hasNext()) {
          if (entries.length == 0) {
            currentIterator = null;
            return null;
          }

          final OHashIndexBucket.Entry<Object, V> bucketEntry = entries[nextEntriesIndex];

          currentKey = bucketEntry.key;

          V value = bucketEntry.value;
          if (valuesTransformer != null)
            currentIterator = valuesTransformer.transformFromValue(value).iterator();
          else
            currentIterator = Collections.singletonList((OIdentifiable) value).iterator();

          nextEntriesIndex++;

          if (nextEntriesIndex >= entries.length) {
            entries = hashTable.higherEntries(entries[entries.length - 1].key);

            nextEntriesIndex = 0;
          }
        }

        if (currentIterator != null && !currentIterator.hasNext())
          return nextCursorValue();

        currentIterator = null;
        return null;
      }

      private Map.Entry<Object, OIdentifiable> nextCursorValue() {
        final OIdentifiable identifiable = currentIterator.next();

        return new Map.Entry<Object, OIdentifiable>() {
          @Override
          public Object getKey() {
            return currentKey;
          }

          @Override
          public OIdentifiable getValue() {
            return identifiable;
          }

          @Override
          public OIdentifiable setValue(OIdentifiable value) {
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }

  @Override
  public OIndexCursor descCursor(final ValuesTransformer<V> valuesTransformer) {
    return new OIndexAbstractCursor() {
      private int                                 nextEntriesIndex;
      private OHashIndexBucket.Entry<Object, V>[] entries;

      private Iterator<OIdentifiable>             currentIterator = new OEmptyIterator<OIdentifiable>();
      private Object                              currentKey;

      {
        OHashIndexBucket.Entry<Object, V> lastEntry = hashTable.lastEntry();
        if (lastEntry == null)
          entries = new OHashIndexBucket.Entry[0];
        else
          entries = hashTable.floorEntries(lastEntry.key);

        if (entries.length == 0)
          currentIterator = null;
      }

      @Override
      public Map.Entry<Object, OIdentifiable> nextEntry() {
        if (currentIterator == null)
          return null;

        if (currentIterator.hasNext())
          return nextCursorValue();

        while (currentIterator != null && !currentIterator.hasNext()) {
          if (entries.length == 0) {
            currentIterator = null;
            return null;
          }

          final OHashIndexBucket.Entry<Object, V> bucketEntry = entries[nextEntriesIndex];

          currentKey = bucketEntry.key;

          V value = bucketEntry.value;
          if (valuesTransformer != null) {
            currentIterator = valuesTransformer.transformFromValue(value).iterator();
          } else
            currentIterator = Collections.singletonList((OIdentifiable) value).iterator();

          nextEntriesIndex--;

          if (nextEntriesIndex < 0) {
            entries = hashTable.lowerEntries(entries[0].key);

            nextEntriesIndex = entries.length - 1;
          }
        }

        if (currentIterator != null && !currentIterator.hasNext())
          return nextCursorValue();

        currentIterator = null;
        return null;
      }

      private Map.Entry<Object, OIdentifiable> nextCursorValue() {
        final OIdentifiable identifiable = currentIterator.next();

        return new Map.Entry<Object, OIdentifiable>() {
          @Override
          public Object getKey() {
            return currentKey;
          }

          @Override
          public OIdentifiable getValue() {
            return identifiable;
          }

          @Override
          public OIdentifiable setValue(OIdentifiable value) {
            throw new UnsupportedOperationException();
          }
        };
      }
    };
  }

  @Override
  public OIndexKeyCursor keyCursor() {
    return new OIndexKeyCursor() {
      private int                                 nextEntriesIndex;
      private OHashIndexBucket.Entry<Object, V>[] entries;

      {
        OHashIndexBucket.Entry<Object, V> firstEntry = hashTable.firstEntry();
        if (firstEntry == null)
          entries = new OHashIndexBucket.Entry[0];
        else
          entries = hashTable.ceilingEntries(firstEntry.key);
      }

      @Override
      public Object next(int prefetchSize) {
        if (entries.length == 0) {
          return null;
        }

        final OHashIndexBucket.Entry<Object, V> bucketEntry = entries[nextEntriesIndex];
        nextEntriesIndex++;
        if (nextEntriesIndex >= entries.length) {
          entries = hashTable.higherEntries(entries[entries.length - 1].key);

          nextEntriesIndex = 0;
        }

        return bucketEntry.key;
      }
    };
  }

  private ODatabaseRecordInternal getDatabase() {
    return ODatabaseRecordThreadLocal.INSTANCE.get();
  }
}
TOP

Related Classes of com.orientechnologies.orient.core.index.engine.OHashTableIndexEngine

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.