Package com.sleepycat.je.rep.utilint

Source Code of com.sleepycat.je.rep.utilint.SizeAwaitMap

/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2002, 2011 Oracle and/or its affiliates.  All rights reserved.
*
*/

package com.sleepycat.je.rep.utilint;

import static com.sleepycat.je.rep.utilint.SizeAwaitMapStatDefinition.N_NO_WAITS;
import static com.sleepycat.je.rep.utilint.SizeAwaitMapStatDefinition.N_REAL_WAITS;
import static com.sleepycat.je.rep.utilint.SizeAwaitMapStatDefinition.N_WAIT_TIME;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import com.sleepycat.je.EnvironmentFailureException;
import com.sleepycat.je.utilint.LongStat;
import com.sleepycat.je.utilint.StatGroup;

/**
* Creates a Map, that Threads can conveniently wait on to reach a specific
* size. The wait functionality is provided by the sizeAwait() method
* defined by this class.
*/
public class SizeAwaitMap<K,V> implements Map<K,V> {

    /*
     * The latch map. There is a latch for each threshold of interest to a
     * thread.
     */
    private final HashMap<Integer,ThresholdLatch> thresholdLatches;

    /* The underlying map of interest to threads. */
    private final Map<K,V> map;

    private final StatGroup stats;
    private final LongStat nNoWaits;
    private final LongStat nRealWaits;
    private final LongStat nWaitTime;

    /**
     * Creates the wrapped Map class. Note that the application must not
     * directly manipulate the underlying map class. The underlying map must
     * be synchronized if it's accessed concurrently.
     *
     * @param map the actual map instance.
     */
    public SizeAwaitMap(Map<K, V> map) {
        thresholdLatches = new HashMap<Integer,ThresholdLatch>();
        this.map = map;
        stats = new StatGroup(SizeAwaitMapStatDefinition.GROUP_NAME,
                              SizeAwaitMapStatDefinition.GROUP_DESC);
        nNoWaits = new LongStat(stats, N_NO_WAITS);
        nRealWaits = new LongStat(stats, N_REAL_WAITS);
        nWaitTime = new LongStat(stats, N_WAIT_TIME);
    }

    public StatGroup getStatistics() {
        return stats;
    }

    /**
     * Causes the requesting thread to wait until the map reaches the specified
     * size or the thread is interrupted.
     *
     * @param thresholdSize the size to wait for.
     *
     * @return true if the threshold was reached, false, if thw ait timed out.
     *
     * @throws InterruptedException for the usual reasons, or if the map
     * was cleared and the size threshold was not actually reached.
     *
     */
    public boolean sizeAwait(int thresholdSize,
                             long timeout,
                             TimeUnit unit)
        throws InterruptedException {

        assert(thresholdSize >= 0);
        ThresholdLatch l = null;
        synchronized (this) {
            int size = map.size();
            if (thresholdSize  <= size) {
                nNoWaits.increment();
                return true;
            }
            l = thresholdLatches.get(thresholdSize);
            if (l == null) {
                l = new ThresholdLatch(1);
                thresholdLatches.put(thresholdSize, l);
            }
        }
        nRealWaits.increment();
        long startTime = System.currentTimeMillis();
        boolean success = l.await(timeout, unit);
        nWaitTime.add((System.currentTimeMillis() - startTime));
        if (l.getLatchCleared()) {
            throw new InterruptedException
            ("Wait was interrupted (the wait latch was explicitly cleared).");
        }
        return success;
    }

    /**
     * Used for unit tests only
     * @return
     */
    synchronized int latchCount() {
        return thresholdLatches.size();
    }

    /**
     * Notes the addition of a new value and counts down any latches that were
     * assigned to that threshold.
     */
    synchronized public V put(K key, V value) {
        V oldValue = map.put(key, value);
        if (oldValue == null) {
            /* Incremented size */
            CountDownLatch l = thresholdLatches.remove(map.size());
            if (l != null) {
                l.countDown();
            }
        }
        return oldValue;
    }

    /**
     * It's synchronized so that size() has a stable value in the above
     * methods.
     */
    synchronized public V remove(Object key) {
        return map.remove(key);
    }

    /**
     * Clears the underlying map and the latch map, after first counting them
     * down, thus permitting them to make progress.
     */
    synchronized public void clear() {
        for (ThresholdLatch l : thresholdLatches.values()) {
            l.setLatchCleared(true);
            l.countDown();
        }
        thresholdLatches.clear();
        map.clear();
    }

    /* The remaining methods below merely forward to the underlying map. */

    public boolean containsKey(Object key) {
        return map.containsKey(key);
    }

    public boolean containsValue(Object value) {
        return map.containsKey(value);
    }

    public Set<java.util.Map.Entry<K, V>> entrySet() {
        return map.entrySet();
    }

    public V get(Object key) {
        return map.get(key);
    }

    public boolean isEmpty() {
        return map.isEmpty();
    }

    public Set<K> keySet() {
        return map.keySet();
    }

    public void putAll(@SuppressWarnings("unused")
                       Map<? extends K, ? extends V> t) {
        throw EnvironmentFailureException.unexpectedState
            ("putAll not supported");
    }

    public int size() {
        return map.size();
    }

    public Collection<V> values() {
        return map.values();
    }

    /**
     * Subtype to keep track of how the latch was cleared.
     */
    class ThresholdLatch extends CountDownLatch {

        /* Set to true if the latch was forcibly cleared. That is,
         * the threshold was not reached.
         */
        private boolean latchCleared = false;

        ThresholdLatch(int count) {
            super(count);
        }

        boolean getLatchCleared() {
            return latchCleared;
        }

        void setLatchCleared(boolean latchCleared) {
            this.latchCleared = latchCleared;
        }

    }
}
TOP

Related Classes of com.sleepycat.je.rep.utilint.SizeAwaitMap

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.