-
Notifications
You must be signed in to change notification settings - Fork 172
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #133 from brharrington/impl-util
move some of the common utils to impl package
- Loading branch information
Showing
6 changed files
with
481 additions
and
0 deletions.
There are no files selected for viewing
109 changes: 109 additions & 0 deletions
109
spectator-api/src/main/java/com/netflix/spectator/impl/AtomicDouble.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
spectator-api/src/main/java/com/netflix/spectator/impl/StepDouble.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() + '}'; | ||
} | ||
} |
79 changes: 79 additions & 0 deletions
79
spectator-api/src/main/java/com/netflix/spectator/impl/StepLong.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() + '}'; | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
spectator-api/src/test/java/com/netflix/spectator/impl/AtomicDoubleTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
|
||
} |
Oops, something went wrong.