Package com.opengamma.engine.cache

Source Code of com.opengamma.engine.cache.CachingIdentifierMap

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.cache;

import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongCollection;
import it.unimi.dsi.fastutil.longs.LongList;
import it.unimi.dsi.fastutil.objects.Object2LongMap;
import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentMap;

import com.google.common.collect.MapMaker;
import com.opengamma.engine.MemoryUtils;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.util.ArgumentChecker;

/**
* Caches value identifiers on top of another identifier source. This class is internally synchronized.
*/
public class CachingIdentifierMap implements IdentifierMap {
  private final IdentifierMap _underlying;
  // NOTE kirk 2010-08-06 -- This INTENTIONALLY is not an EHCache instance.
  // Since getting a remote value specification identifier has to be a super-fast operation
  // (probably faster than disk anyway), and the only reason we'd ever want to flush is
  // based on low GCs, and the elements are so small, EHCache doesn't actually work here.

  // NOTE andrew 2010-09-06 -- Don't use the Google map with weakKeys; it will do comparison by identity which isn't right!
  private final Map<ValueSpecification, Long> _specificationToIdentifier = Collections.synchronizedMap(new WeakHashMap<ValueSpecification, Long>());
  private final ConcurrentMap<Long, ValueSpecification> _identifierToSpecification = new MapMaker().softValues().makeMap();

  public CachingIdentifierMap(IdentifierMap underlying) {
    ArgumentChecker.notNull(underlying, "Underlying source");
    _underlying = underlying;
  }

  /**
   * Gets the underlying source.
   *
   * @return the underlying
   */
  public IdentifierMap getUnderlying() {
    return _underlying;
  }

  @Override
  public long getIdentifier(final ValueSpecification spec) {
    Long value = _specificationToIdentifier.get(spec);
    if (value != null) {
      return value.longValue();
    }
    long longValue = getUnderlying().getIdentifier(spec);
    value = longValue;
    _specificationToIdentifier.put(spec, value);
    _identifierToSpecification.put(value, spec);
    return longValue;
  }

  @Override
  public Object2LongMap<ValueSpecification> getIdentifiers(Collection<ValueSpecification> specs) {
    final Object2LongMap<ValueSpecification> identifiers = new Object2LongOpenHashMap<ValueSpecification>();
    List<ValueSpecification> cacheMisses = null;
    for (ValueSpecification spec : specs) {
      Long value = _specificationToIdentifier.get(spec);
      if (value != null) {
        identifiers.put(spec, value.longValue());
      } else {
        if (cacheMisses == null) {
          cacheMisses = new LinkedList<ValueSpecification>();
        }
        cacheMisses.add(MemoryUtils.instance(spec));
      }
    }
    if (cacheMisses != null) {
      if (cacheMisses.size() == 1) {
        final ValueSpecification spec = cacheMisses.get(0);
        final long value = getUnderlying().getIdentifier(spec);
        final Long keyValue = value;
        _specificationToIdentifier.put(spec, keyValue);
        _identifierToSpecification.put(keyValue, spec);
        identifiers.put(spec, value);
      } else {
        final Object2LongMap<ValueSpecification> values = getUnderlying().getIdentifiers(cacheMisses);
        for (Object2LongMap.Entry<ValueSpecification> entry : values.object2LongEntrySet()) {
          final Long value = entry.getValue();
          _specificationToIdentifier.put(entry.getKey(), value);
          _identifierToSpecification.put(value, entry.getKey());
        }
        identifiers.putAll(values);
      }
    }
    return identifiers;
  }

  @Override
  public ValueSpecification getValueSpecification(final long identifier) {
    final Long key = identifier;
    ValueSpecification spec = _identifierToSpecification.get(key);
    if (spec != null) {
      return spec;
    }
    spec = getUnderlying().getValueSpecification(identifier);
    _specificationToIdentifier.put(spec, key);
    _identifierToSpecification.put(key, spec);
    return spec;
  }

  @Override
  public Long2ObjectMap<ValueSpecification> getValueSpecifications(LongCollection identifiers) {
    final Long2ObjectMap<ValueSpecification> specifications = new Long2ObjectOpenHashMap<ValueSpecification>();
    LongList cacheMisses = null;
    for (long identifier : identifiers) {
      final Long key = identifier;
      final ValueSpecification specification = _identifierToSpecification.get(key);
      if (specification != null) {
        specifications.put(identifier, specification);
      } else {
        if (cacheMisses == null) {
          cacheMisses = new LongArrayList(identifiers.size());
        }
        cacheMisses.add(identifier);
      }
    }
    if (cacheMisses != null) {
      if (cacheMisses.size() == 1) {
        final long identifier = cacheMisses.getLong(0);
        final ValueSpecification specification = getUnderlying().getValueSpecification(identifier);
        final Long key = identifier;
        _specificationToIdentifier.put(specification, key);
        _identifierToSpecification.put(key, specification);
        specifications.put(identifier, specification);
      } else {
        final Long2ObjectMap<ValueSpecification> values = getUnderlying().getValueSpecifications(cacheMisses);
        for (Long2ObjectMap.Entry<ValueSpecification> entry : values.long2ObjectEntrySet()) {
          final Long value = entry.getKey();
          _specificationToIdentifier.put(entry.getValue(), value);
          _identifierToSpecification.put(value, entry.getValue());
        }
        specifications.putAll(values);
      }
    }
    return specifications;
  }

}
TOP

Related Classes of com.opengamma.engine.cache.CachingIdentifierMap

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.