blob: fd37bcb12302a4a73d42abdb98a9fee5b9ad5765 [file] [log] [blame]
/*-
* Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle Berkeley
* DB Java Edition made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle Berkeley DB Java Edition for a copy of the
* license and additional information.
*/
package com.sleepycat.je.utilint;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicLong;
import com.sleepycat.je.utilint.StatDefinition.StatType;
/**
* A JE stat that maintains a map of individual values based on AtomicLong
* which can be looked up with a String key, and that returns results as a
* formatted string.
*/
public final class AtomicLongMapStat
extends MapStat<Long, AtomicLongComponent> {
private static final long serialVersionUID = 1L;
/**
* Creates an instance of this class.
*
* @param group the owning group
* @param definition the associated definition
*/
public AtomicLongMapStat(StatGroup group, StatDefinition definition) {
super(group, definition);
}
private AtomicLongMapStat(AtomicLongMapStat other) {
super(other);
}
/**
* Creates, stores, and returns a new stat for the specified key.
*
* @param key the key
* @return the new stat
*/
public synchronized AtomicLongComponent createStat(String key) {
assert key != null;
final AtomicLongComponent stat = new AtomicLongComponent();
statMap.put(key, stat);
return stat;
}
@Override
public AtomicLongMapStat copy() {
return new AtomicLongMapStat(this);
}
/** The base argument must be an instance of AtomicLongMapStat. */
@Override
public AtomicLongMapStat computeInterval(Stat<String> base) {
assert base instanceof AtomicLongMapStat;
final AtomicLongMapStat copy = copy();
if (definition.getType() != StatType.INCREMENTAL) {
return copy;
}
final AtomicLongMapStat baseMapStat = (AtomicLongMapStat) base;
synchronized (copy) {
for (final Entry<String, AtomicLongComponent> entry :
copy.statMap.entrySet()) {
final AtomicLongComponent baseValue;
synchronized (baseMapStat) {
baseValue = baseMapStat.statMap.get(entry.getKey());
}
if (baseValue != null) {
final AtomicLongComponent entryValue = entry.getValue();
entryValue.val.getAndAdd(-baseValue.get());
}
}
}
return copy;
}
@Override
public synchronized void negate() {
if (definition.getType() == StatType.INCREMENTAL) {
for (final AtomicLongComponent stat : statMap.values()) {
final AtomicLong atomicVal = stat.val;
/*
* Negate the value atomically, retrying if another change
* intervenes. This loop emulates the behavior of
* AtomicLong.getAndIncrement.
*/
while (true) {
final long val = atomicVal.get();
if (atomicVal.compareAndSet(val, -val)) {
break;
}
}
}
}
}
}