/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.view.worker.cache;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.threeten.bp.Instant;
import com.google.common.collect.MapMaker;
import com.opengamma.id.VersionCorrection;
import com.opengamma.util.WeakInstanceCache;
import com.opengamma.util.map.HashMap2;
import com.opengamma.util.map.Map2;
import com.opengamma.util.map.WeakValueHashMap2;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
* Provides locks that correspond to the view execution cache keys.
* <p>
* Once a key has returned a lock, all the while that lock is in scope any keys that are equal will return the same lock instance.
*/
public final class ViewExecutionCacheLock {
// No harm in sharing the canonicalized forms with other instances.
private static final WeakInstanceCache<ViewExecutionCacheKey> s_keys = new WeakInstanceCache<ViewExecutionCacheKey>();
private static final class Locks {
private final Lock _broad = new ReentrantLock();
private final Map2<VersionCorrection, Instant, Lock> _fine = new WeakValueHashMap2<VersionCorrection, Instant, Lock>(HashMap2.STRONG_KEYS);
}
// The actual lock objects are per instance
private final ConcurrentMap<ViewExecutionCacheKey, Locks> _locks = new MapMaker().weakKeys().makeMap();
private Locks getOrCreateLocks(final ViewExecutionCacheKey cacheKey) {
final ViewExecutionCacheKey normalized = s_keys.get(cacheKey);
Locks locks = _locks.get(normalized);
if (locks == null) {
locks = new Locks();
final Locks previous = _locks.putIfAbsent(normalized, locks);
if (previous != null) {
locks = previous;
}
}
return locks;
}
/**
* Acquires the broad lock for the view compilation.
*
* @param cacheKey the broad key that summarizes the view definition and market data providers, not null
* @return the lock instance, not null
*/
public Lock get(final ViewExecutionCacheKey cacheKey) {
return getOrCreateLocks(cacheKey)._broad;
}
/**
* Acquires the broad and finer grained locks for a specific compilation of a view
*
* @param cacheKey the broad key that summarizes the view definition and market data providers, not null
* @param valuationTime an indicative valuation time for any compilation, not null
* @param resolverVersionCorrection the target resolver version/correction timestamp, not null
* @return the lock instances, not null. The first element in the pair is the broad lock, the second is the finer lock
*/
public Pair<Lock, Lock> get(final ViewExecutionCacheKey cacheKey, final Instant valuationTime, final VersionCorrection resolverVersionCorrection) {
final Locks locks = getOrCreateLocks(cacheKey);
Lock lock = locks._fine.get(resolverVersionCorrection, valuationTime);
if (lock == null) {
lock = new ReentrantLock();
final Lock previous = locks._fine.putIfAbsent(resolverVersionCorrection, valuationTime, lock);
if (previous != null) {
lock = previous;
}
}
return Pairs.of(locks._broad, lock);
}
}