<commit_before>/*
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.util;

import com.google.common.primitives.UnsignedLong;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * Concurrent version of {@link DurationStatisticsTracker}.
 */
// TODO: once DurationStatsTracker is gone make this class final
class ConcurrentDurationStatisticsTracker extends DurationStatisticsTracker {

    private static final AtomicReferenceFieldUpdater<ConcurrentDurationStatisticsTracker, DurationWithTime>
        LONGEST_UPDATER = AtomicReferenceFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class,
                DurationWithTime.class, "longest");

    private static final AtomicReferenceFieldUpdater<ConcurrentDurationStatisticsTracker, DurationWithTime>
        SHORTEST_UPDATER = AtomicReferenceFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class,
                DurationWithTime.class, "shortest");

    private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> COUNT_UPDATER =
            AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "count");
    private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> SUM_UPDATER =
            AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "sum");

    private volatile long sum = 0;
    private volatile long count = 0;
    private volatile DurationWithTime longest = null;
    private volatile DurationWithTime shortest = null;

    ConcurrentDurationStatisticsTracker() {
        // Hidden on purpose
    }

    @Override
    public final void addDuration(final long duration) {
        // First update the quick stats
        SUM_UPDATER.addAndGet(this, duration);
        COUNT_UPDATER.incrementAndGet(this);

        /*
         * Now the hairy 'min/max' things. The notion of "now" we cache,
         * so the first time we use it, we do not call it twice. We populate
         * it lazily, though.
         *
         * The longest/shortest stats both are encapsulated in an object,
         * so we update them atomically and we minimize the number of volatile
         * operations.
         */
        DurationWithTime current = shortest;
        if (current == null || duration < current.getDuration()) {
            final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
            while (!SHORTEST_UPDATER.weakCompareAndSet(this, current, newObj)) {
                current = shortest;
                if (current != null && duration >= current.getDuration()) {
                    break;
                }
            }
        }

        current = longest;
        if (current == null || duration > current.getDuration()) {
            final DurationWithTime newObj = new DurationWithTime(duration, System.currentTimeMillis());
            while (!LONGEST_UPDATER.weakCompareAndSet(this, current, newObj)) {
                current = longest;
                if (current != null && duration <= current.getDuration()) {
                    break;
                }
            }
        }
    }

    @Override
    public final long getTotalDurations() {<commit_msg>Use VarHandles to update shortest/longest duration<commit_after>/*
 * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 */
package org.opendaylight.yangtools.util;

import com.google.common.primitives.UnsignedLong;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;

/**
 * Concurrent version of {@link DurationStatisticsTracker}.
 */
// TODO: once DurationStatsTracker is gone make this class final
class ConcurrentDurationStatisticsTracker extends DurationStatisticsTracker {
    private static final VarHandle LONGEST;
    private static final VarHandle SHORTEST;

    static {
        final var lookup = MethodHandles.lookup();
        try {
            LONGEST = lookup.findVarHandle(
                ConcurrentDurationStatisticsTracker.class, "longest", DurationWithTime.class);
            SHORTEST = lookup.findVarHandle(
                ConcurrentDurationStatisticsTracker.class, "shortest", DurationWithTime.class);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new ExceptionInInitializerError(e);
        }
    }

    private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> COUNT_UPDATER =
            AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "count");
    private static final AtomicLongFieldUpdater<ConcurrentDurationStatisticsTracker> SUM_UPDATER =
            AtomicLongFieldUpdater.newUpdater(ConcurrentDurationStatisticsTracker.class, "sum");

    private volatile long sum = 0;
    private volatile long count = 0;
    private volatile DurationWithTime longest;
    private volatile DurationWithTime shortest;

    ConcurrentDurationStatisticsTracker() {
        // Hidden on purpose
    }

    @Override
    public final void addDuration(final long duration) {
        // First update the quick stats
        SUM_UPDATER.addAndGet(this, duration);
        COUNT_UPDATER.incrementAndGet(this);

        /*
         * Now the hairy 'min/max' things. The notion of "now" we cache, so the first time we use it, we do not call it
         * twice. We populate it lazily, though.
         *
         * The longest/shortest stats both are encapsulated in an object, so we update them atomically and we minimize
         * the number of volatile operations.
         */
        final var currentShortest = (DurationWithTime) SHORTEST.getAcquire(this);
        if (currentShortest == null || duration < currentShortest.getDuration()) {
            updateShortest(currentShortest, duration);
        }
        final var currentLongest = (DurationWithTime) LONGEST.getAcquire(this);
        if (currentLongest == null || duration > currentLongest.getDuration()) {
            updateLongest(currentLongest, duration);
        }
    }

    private void updateShortest(final DurationWithTime prev, final long duration) {
        final var newObj = new DurationWithTime(duration, System.currentTimeMillis());

        var expected = prev;
        while (true) {
            final var witness = (DurationWithTime) SHORTEST.compareAndExchangeRelease(this, expected, newObj);
            if (witness == expected || duration >= witness.getDuration()) {
                break;
            }
            expected = witness;
        }
    }

    private void updateLongest(final DurationWithTime prev, final long duration) {
        final var newObj = new DurationWithTime(duration, System.currentTimeMillis());

        var expected = prev;
        while (true) {
            final var witness = (DurationWithTime) LONGEST.compareAndExchangeRelease(this, expected, newObj);
            if (witness == expected || duration <= witness.getDuration()) {
                break;
            }
            expected = witness;
        }
    }

    @Override
    public final long getTotalDurations() {
{'fraction_non_alphanumeric': 0.076171875, 'fraction_numerical': 0.0026041666666666665, 'mean_word_length': 2.971561530506722, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3639088', 'n_tokens_mistral': 1984, 'n_tokens_neox': 1892, 'n_words': 547}