Skip to content

Commit

Permalink
Merge pull request #133 from brharrington/impl-util
Browse files Browse the repository at this point in the history
move some of the common utils to impl package
  • Loading branch information
brharrington committed Mar 9, 2015
2 parents 5e97842 + 5e311bf commit 698e62e
Show file tree
Hide file tree
Showing 6 changed files with 481 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.spectator.impl;

import java.util.concurrent.atomic.AtomicLong;

/**
* Wrapper around AtomicLong to make working with double values easier.
*/
public class AtomicDouble extends Number {

private final AtomicLong value;

/** Create an instance with an initial value of 0. */
public AtomicDouble() {
this(0.0);
}

/** Create an instance with an initial value of {@code init}. */
public AtomicDouble(double init) {
super();
value = new AtomicLong(Double.doubleToLongBits(init));
}

/** Return the current value. */
public double get() {
return Double.longBitsToDouble(value.get());
}

/** Add {@code amount} to the value and return the new value. */
public double addAndGet(double amount) {
long v;
double d;
double n;
long next;
do {
v = value.get();
d = Double.longBitsToDouble(v);
n = d + amount;
next = Double.doubleToLongBits(n);
} while (!value.compareAndSet(v, next));
return n;
}

/** Add {@code amount} to the value and return the previous value. */
public double getAndAdd(double amount) {
long v;
double d;
double n;
long next;
do {
v = value.get();
d = Double.longBitsToDouble(v);
n = d + amount;
next = Double.doubleToLongBits(n);
} while (!value.compareAndSet(v, next));
return d;
}

/** Set the value to {@code amount} and return the previous value. */
public double getAndSet(double amount) {
long v = value.getAndSet(Double.doubleToLongBits(amount));
return Double.longBitsToDouble(v);
}

/**
* Set the value to {@code amount} if the current value is {@code expect}. Return true if the
* value was updated.
*/
public boolean compareAndSet(double expect, double update) {
long e = Double.doubleToLongBits(expect);
long u = Double.doubleToLongBits(update);
return value.compareAndSet(e, u);
}

/** Set the current value to {@code amount}. */
public void set(double amount) {
value.set(Double.doubleToLongBits(amount));
}

@Override public int intValue() {
return (int) get();
}

@Override public long longValue() {
return (long) get();
}

@Override public float floatValue() {
return (float) get();
}

@Override public double doubleValue() {
return get();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.spectator.impl;

import com.netflix.spectator.api.Clock;

import java.util.concurrent.atomic.AtomicLong;

/**
* Utility class for managing a set of AtomicLong instances mapped to a particular step interval.
* The current implementation keeps an array of with two items where one is the current value
* being updated and the other is the value from the previous interval and is only available for
* polling.
*/
public class StepDouble {

private final double init;
private final Clock clock;
private final long step;

private final AtomicDouble previous;
private final AtomicDouble current;

private final AtomicLong lastInitPos;

/** Create a new instance. */
public StepDouble(double init, Clock clock, long step) {
this.init = init;
this.clock = clock;
this.step = step;
previous = new AtomicDouble(init);
current = new AtomicDouble(init);
lastInitPos = new AtomicLong(clock.wallTime() / step);
}

private void rollCount(long now) {
final long stepTime = now / step;
final long lastInit = lastInitPos.get();
if (lastInit < stepTime && lastInitPos.compareAndSet(lastInit, stepTime)) {
final double v = current.getAndSet(init);
// Need to check if there was any activity during the previous step interval. If there was
// then the init position will move forward by 1, otherwise it will be older. No activity
// means the previous interval should be set to the `init` value.
previous.set((lastInit == stepTime - 1) ? v : init);
}
}

/** Get the AtomicDouble for the current bucket. */
public AtomicDouble getCurrent() {
rollCount(clock.wallTime());
return current;
}

/** Get the value for the last completed interval. */
public double poll() {
rollCount(clock.wallTime());
return previous.get();
}

@Override public String toString() {
return "StepLong{init=" + init
+ ", previous=" + previous.get()
+ ", current=" + current.get()
+ ", lastInitPos=" + lastInitPos.get() + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.spectator.impl;

import com.netflix.spectator.api.Clock;

import java.util.concurrent.atomic.AtomicLong;

/**
* Utility class for managing a set of AtomicLong instances mapped to a particular step interval.
* The current implementation keeps an array of with two items where one is the current value
* being updated and the other is the value from the previous interval and is only available for
* polling.
*/
public class StepLong {

private final long init;
private final Clock clock;
private final long step;

private final AtomicLong previous;
private final AtomicLong current;

private final AtomicLong lastInitPos;

/** Create a new instance. */
public StepLong(long init, Clock clock, long step) {
this.init = init;
this.clock = clock;
this.step = step;
previous = new AtomicLong(init);
current = new AtomicLong(init);
lastInitPos = new AtomicLong(clock.wallTime() / step);
}

private void rollCount(long now) {
final long stepTime = now / step;
final long lastInit = lastInitPos.get();
if (lastInit < stepTime && lastInitPos.compareAndSet(lastInit, stepTime)) {
final long v = current.getAndSet(init);
// Need to check if there was any activity during the previous step interval. If there was
// then the init position will move forward by 1, otherwise it will be older. No activity
// means the previous interval should be set to the `init` value.
previous.set((lastInit == stepTime - 1) ? v : init);
}
}

/** Get the AtomicLong for the current bucket. */
public AtomicLong getCurrent() {
rollCount(clock.wallTime());
return current;
}

/** Get the value for the last completed interval. */
public long poll() {
rollCount(clock.wallTime());
return previous.get();
}

@Override public String toString() {
return "StepLong{init=" + init
+ ", previous=" + previous.get()
+ ", current=" + current.get()
+ ", lastInitPos=" + lastInitPos.get() + '}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright 2015 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.spectator.impl;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class AtomicDoubleTest {

@Test
public void init() {
AtomicDouble v = new AtomicDouble();
Assert.assertEquals(0.0, v.get(), 1e-12);
}

@Test
public void initWithValue() {
AtomicDouble v = new AtomicDouble(42.0);
Assert.assertEquals(42.0, v.get(), 1e-12);
}

@Test
public void set() {
AtomicDouble v = new AtomicDouble(13.0);
v.set(42.0);
Assert.assertEquals(42.0, v.get(), 1e-12);
}

@Test
public void getAndSet() {
AtomicDouble v = new AtomicDouble(13.0);
Assert.assertEquals(13.0, v.getAndSet(42.0), 1e-12);
Assert.assertEquals(42.0, v.get(), 1e-12);
}

@Test
public void compareAndSet() {
AtomicDouble v = new AtomicDouble(13.0);
Assert.assertTrue(v.compareAndSet(13.0, 42.0));
Assert.assertEquals(42.0, v.get(), 1e-12);
}

@Test
public void compareAndSetFail() {
AtomicDouble v = new AtomicDouble(13.0);
Assert.assertFalse(v.compareAndSet(12.0, 42.0));
Assert.assertEquals(13.0, v.get(), 1e-12);
}

@Test
public void addAndGet() {
AtomicDouble v = new AtomicDouble(13.0);
Assert.assertEquals(55.0, v.addAndGet(42.0), 1e-12);
Assert.assertEquals(55.0, v.get(), 1e-12);
}

@Test
public void getAndAdd() {
AtomicDouble v = new AtomicDouble(13.0);
Assert.assertEquals(13.0, v.getAndAdd(42.0), 1e-12);
Assert.assertEquals(55.0, v.get(), 1e-12);
}

}
Loading

0 comments on commit 698e62e

Please sign in to comment.