Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -15,7 +15,7 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.cluster.flow.statistic.data; | package com.alibaba.csp.sentinel.cluster.flow.statistic.data; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import java.util.concurrent.atomic.LongAdder; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
@@ -16,9 +16,9 @@ | |||||
package com.alibaba.csp.sentinel.cluster.flow.statistic.limit; | package com.alibaba.csp.sentinel.cluster.flow.statistic.limit; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.concurrent.atomic.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.UnaryLeapArray; | import com.alibaba.csp.sentinel.slots.statistic.base.UnaryLeapArray; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
@@ -15,10 +15,11 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.cluster.flow.statistic.metric; | package com.alibaba.csp.sentinel.cluster.flow.statistic.metric; | ||||
import java.util.concurrent.atomic.LongAdder; | |||||
import com.alibaba.csp.sentinel.cluster.flow.statistic.data.ClusterFlowEvent; | import com.alibaba.csp.sentinel.cluster.flow.statistic.data.ClusterFlowEvent; | ||||
import com.alibaba.csp.sentinel.cluster.flow.statistic.data.ClusterMetricBucket; | import com.alibaba.csp.sentinel.cluster.flow.statistic.data.ClusterMetricBucket; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | ||||
/** | /** | ||||
@@ -15,13 +15,19 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.cluster.flow.statistic.metric; | package com.alibaba.csp.sentinel.cluster.flow.statistic.metric; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import java.util.ArrayList; | |||||
import java.util.Collections; | |||||
import java.util.Comparator; | |||||
import java.util.HashMap; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.Map.Entry; | |||||
import java.util.Set; | |||||
import java.util.concurrent.atomic.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.cache.CacheMap; | import com.alibaba.csp.sentinel.slots.statistic.cache.CacheMap; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
import java.util.*; | |||||
import java.util.Map.Entry; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
* @since 1.4.0 | * @since 1.4.0 | ||||
@@ -16,8 +16,7 @@ | |||||
package com.alibaba.csp.sentinel.eagleeye; | package com.alibaba.csp.sentinel.eagleeye; | ||||
import java.util.concurrent.atomic.AtomicReference; | import java.util.concurrent.atomic.AtomicReference; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import java.util.concurrent.atomic.LongAdder; | |||||
interface StatEntryFunc { | interface StatEntryFunc { | ||||
@@ -15,17 +15,17 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.node; | package com.alibaba.csp.sentinel.node; | ||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
import java.util.concurrent.atomic.LongAdder; | |||||
import com.alibaba.csp.sentinel.node.metric.MetricNode; | import com.alibaba.csp.sentinel.node.metric.MetricNode; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric; | import com.alibaba.csp.sentinel.slots.statistic.metric.ArrayMetric; | ||||
import com.alibaba.csp.sentinel.slots.statistic.metric.Metric; | import com.alibaba.csp.sentinel.slots.statistic.metric.Metric; | ||||
import com.alibaba.csp.sentinel.util.TimeUtil; | import com.alibaba.csp.sentinel.util.TimeUtil; | ||||
import com.alibaba.csp.sentinel.util.function.Predicate; | import com.alibaba.csp.sentinel.util.function.Predicate; | ||||
import java.util.List; | |||||
import java.util.Map; | |||||
import java.util.concurrent.ConcurrentHashMap; | |||||
/** | /** | ||||
* <p>The statistic node keep three kinds of real-time statistics metrics:</p> | * <p>The statistic node keep three kinds of real-time statistics metrics:</p> | ||||
* <ol> | * <ol> | ||||
@@ -16,18 +16,17 @@ | |||||
package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker; | package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.concurrent.atomic.LongAdder; | |||||
import com.alibaba.csp.sentinel.Entry; | import com.alibaba.csp.sentinel.Entry; | ||||
import com.alibaba.csp.sentinel.context.Context; | import com.alibaba.csp.sentinel.context.Context; | ||||
import com.alibaba.csp.sentinel.slotchain.ResourceWrapper; | |||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; | import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO; | |||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT; | import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT; | ||||
import static com.alibaba.csp.sentinel.slots.block.RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
@@ -16,13 +16,13 @@ | |||||
package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker; | package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.concurrent.atomic.LongAdder; | |||||
import com.alibaba.csp.sentinel.Entry; | import com.alibaba.csp.sentinel.Entry; | ||||
import com.alibaba.csp.sentinel.context.Context; | import com.alibaba.csp.sentinel.context.Context; | ||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant; | import com.alibaba.csp.sentinel.slots.block.RuleConstant; | ||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; | import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | import com.alibaba.csp.sentinel.slots.statistic.base.LeapArray; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | import com.alibaba.csp.sentinel.slots.statistic.base.WindowWrap; | ||||
import com.alibaba.csp.sentinel.util.AssertUtil; | import com.alibaba.csp.sentinel.util.AssertUtil; | ||||
import com.alibaba.csp.sentinel.util.TimeUtil; | import com.alibaba.csp.sentinel.util.TimeUtil; | ||||
@@ -1,213 +0,0 @@ | |||||
package com.alibaba.csp.sentinel.slots.statistic.base; | |||||
/* | |||||
* Written by Doug Lea with assistance from members of JCP JSR-166 | |||||
* Expert Group and released to the public domain, as explained at | |||||
* http://creativecommons.org/publicdomain/zero/1.0/ | |||||
* | |||||
* From http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/ | |||||
*/ | |||||
import java.io.IOException; | |||||
import java.io.ObjectInputStream; | |||||
import java.io.Serializable; | |||||
import java.util.concurrent.atomic.AtomicLong; | |||||
/** | |||||
* One or more variables that together maintain an initially zero | |||||
* {@code long} sum. When updates (method {@link #add}) are contended | |||||
* across threads, the set of variables may grow dynamically to reduce | |||||
* contention. Method {@link #sum} (or, equivalently, {@link | |||||
* #longValue}) returns the current total combined across the | |||||
* variables maintaining the sum. | |||||
* | |||||
* <p> This class is usually preferable to {@link AtomicLong} when | |||||
* multiple threads update a common sum that is used for purposes such | |||||
* as collecting statistics, not for fine-grained synchronization | |||||
* control. Under low update contention, the two classes have similar | |||||
* characteristics. But under high contention, expected throughput of | |||||
* this class is significantly higher, at the expense of higher space | |||||
* consumption. | |||||
* | |||||
* <p>This class extends {@link Number}, but does <em>not</em> define | |||||
* methods such as {@code hashCode} and {@code compareTo} because | |||||
* instances are expected to be mutated, and so are not useful as | |||||
* collection keys. | |||||
* | |||||
* <p><em>jsr166e note: This class is targeted to be placed in | |||||
* java.util.concurrent.atomic<em> | |||||
* | |||||
* @author Doug Lea | |||||
* @since 1.8 | |||||
*/ | |||||
public class LongAdder extends Striped64 implements Serializable { | |||||
private static final long serialVersionUID = 7249069246863182397L; | |||||
/** | |||||
* Version of plus for use in retryUpdate | |||||
*/ | |||||
@Override | |||||
final long fn(long v, long x) { return v + x; } | |||||
/** | |||||
* Creates a new adder with initial sum of zero. | |||||
*/ | |||||
public LongAdder() { | |||||
} | |||||
/** | |||||
* Adds the given value. | |||||
* | |||||
* @param x the value to add | |||||
*/ | |||||
public void add(long x) { | |||||
Cell[] as; | |||||
long b, v; | |||||
HashCode hc; | |||||
Cell a; | |||||
int n; | |||||
if ((as = cells) != null || !casBase(b = base, b + x)) { | |||||
boolean uncontended = true; | |||||
int h = (hc = threadHashCode.get()).code; | |||||
if (as == null || (n = as.length) < 1 || | |||||
(a = as[(n - 1) & h]) == null || | |||||
!(uncontended = a.cas(v = a.value, v + x))) { retryUpdate(x, hc, uncontended); } | |||||
} | |||||
} | |||||
/** | |||||
* Equivalent to {@code add(1)}. | |||||
*/ | |||||
public void increment() { | |||||
add(1L); | |||||
} | |||||
/** | |||||
* Equivalent to {@code add(-1)}. | |||||
*/ | |||||
public void decrement() { | |||||
add(-1L); | |||||
} | |||||
/** | |||||
* Returns the current sum. The returned value is <em>NOT</em> an | |||||
* atomic snapshot: Invocation in the absence of concurrent | |||||
* updates returns an accurate result, but concurrent updates that | |||||
* occur while the sum is being calculated might not be | |||||
* incorporated. | |||||
* | |||||
* @return the sum | |||||
*/ | |||||
public long sum() { | |||||
long sum = base; | |||||
Cell[] as = cells; | |||||
if (as != null) { | |||||
int n = as.length; | |||||
for (int i = 0; i < n; ++i) { | |||||
Cell a = as[i]; | |||||
if (a != null) { sum += a.value; } | |||||
} | |||||
} | |||||
return sum; | |||||
} | |||||
/** | |||||
* Resets variables maintaining the sum to zero. This method may | |||||
* be a useful alternative to creating a new adder, but is only | |||||
* effective if there are no concurrent updates. Because this | |||||
* method is intrinsically racy, it should only be used when it is | |||||
* known that no threads are concurrently updating. | |||||
*/ | |||||
public void reset() { | |||||
internalReset(0L); | |||||
} | |||||
/** | |||||
* Equivalent in effect to {@link #sum} followed by {@link | |||||
* #reset}. This method may apply for example during quiescent | |||||
* points between multithreaded computations. If there are | |||||
* updates concurrent with this method, the returned value is | |||||
* <em>not</em> guaranteed to be the final value occurring before | |||||
* the reset. | |||||
* | |||||
* @return the sum | |||||
*/ | |||||
public long sumThenReset() { | |||||
long sum = base; | |||||
Cell[] as = cells; | |||||
base = 0L; | |||||
if (as != null) { | |||||
int n = as.length; | |||||
for (int i = 0; i < n; ++i) { | |||||
Cell a = as[i]; | |||||
if (a != null) { | |||||
sum += a.value; | |||||
a.value = 0L; | |||||
} | |||||
} | |||||
} | |||||
return sum; | |||||
} | |||||
/** | |||||
* Returns the String representation of the {@link #sum}. | |||||
* | |||||
* @return the String representation of the {@link #sum} | |||||
*/ | |||||
@Override | |||||
public String toString() { | |||||
return Long.toString(sum()); | |||||
} | |||||
/** | |||||
* Equivalent to {@link #sum}. | |||||
* | |||||
* @return the sum | |||||
*/ | |||||
@Override | |||||
public long longValue() { | |||||
return sum(); | |||||
} | |||||
/** | |||||
* Returns the {@link #sum} as an {@code int} after a narrowing | |||||
* primitive conversion. | |||||
*/ | |||||
@Override | |||||
public int intValue() { | |||||
return (int)sum(); | |||||
} | |||||
/** | |||||
* Returns the {@link #sum} as a {@code float} | |||||
* after a widening primitive conversion. | |||||
*/ | |||||
@Override | |||||
public float floatValue() { | |||||
return (float)sum(); | |||||
} | |||||
/** | |||||
* Returns the {@link #sum} as a {@code double} after a widening | |||||
* primitive conversion. | |||||
*/ | |||||
@Override | |||||
public double doubleValue() { | |||||
return (double)sum(); | |||||
} | |||||
private void writeObject(java.io.ObjectOutputStream s) | |||||
throws java.io.IOException { | |||||
s.defaultWriteObject(); | |||||
s.writeLong(sum()); | |||||
} | |||||
private void readObject(ObjectInputStream s) | |||||
throws IOException, ClassNotFoundException { | |||||
s.defaultReadObject(); | |||||
busy = 0; | |||||
cells = null; | |||||
base = s.readLong(); | |||||
} | |||||
} |
@@ -1,349 +0,0 @@ | |||||
package com.alibaba.csp.sentinel.slots.statistic.base; | |||||
/* | |||||
* Written by Doug Lea with assistance from members of JCP JSR-166 | |||||
* Expert Group and released to the public domain, as explained at | |||||
* http://creativecommons.org/publicdomain/zero/1.0/ | |||||
* | |||||
* From http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/ | |||||
*/ | |||||
import java.util.Random; | |||||
/** | |||||
* A package-local class holding common representation and mechanics | |||||
* for classes supporting dynamic striping on 64bit values. The class | |||||
* extends Number so that concrete subclasses must publicly do so. | |||||
*/ | |||||
abstract class Striped64 extends Number { | |||||
/* | |||||
* This class maintains a lazily-initialized table of atomically | |||||
* updated variables, plus an extra "base" field. The table size | |||||
* is a power of two. Indexing uses masked per-thread hash codes. | |||||
* Nearly all declarations in this class are package-private, | |||||
* accessed directly by subclasses. | |||||
* | |||||
* Table entries are of class Cell; a variant of AtomicLong padded | |||||
* to reduce cache contention on most processors. Padding is | |||||
* overkill for most Atomics because they are usually irregularly | |||||
* scattered in memory and thus don't interfere much with each | |||||
* other. But Atomic objects residing in arrays will tend to be | |||||
* placed adjacent to each other, and so will most often share | |||||
* cache lines (with a huge negative performance impact) without | |||||
* this precaution. | |||||
* | |||||
* In part because Cells are relatively large, we avoid creating | |||||
* them until they are needed. When there is no contention, all | |||||
* updates are made to the base field. Upon first contention (a | |||||
* failed CAS on base update), the table is initialized to size 2. | |||||
* The table size is doubled upon further contention until | |||||
* reaching the nearest power of two greater than or equal to the | |||||
* number of CPUS. Table slots remain empty (null) until they are | |||||
* needed. | |||||
* | |||||
* A single spinlock ("busy") is used for initializing and | |||||
* resizing the table, as well as populating slots with new Cells. | |||||
* There is no need for a blocking lock: When the lock is not | |||||
* available, threads try other slots (or the base). During these | |||||
* retries, there is increased contention and reduced locality, | |||||
* which is still better than alternatives. | |||||
* | |||||
* Per-thread hash codes are initialized to random values. | |||||
* Contention and/or table collisions are indicated by failed | |||||
* CASes when performing an update operation (see method | |||||
* retryUpdate). Upon a collision, if the table size is less than | |||||
* the capacity, it is doubled in size unless some other thread | |||||
* holds the lock. If a hashed slot is empty, and lock is | |||||
* available, a new Cell is created. Otherwise, if the slot | |||||
* exists, a CAS is tried. Retries proceed by "double hashing", | |||||
* using a secondary hash (Marsaglia XorShift) to try to find a | |||||
* free slot. | |||||
* | |||||
* The table size is capped because, when there are more threads | |||||
* than CPUs, supposing that each thread were bound to a CPU, | |||||
* there would exist a perfect hash function mapping threads to | |||||
* slots that eliminates collisions. When we reach capacity, we | |||||
* search for this mapping by randomly varying the hash codes of | |||||
* colliding threads. Because search is random, and collisions | |||||
* only become known via CAS failures, convergence can be slow, | |||||
* and because threads are typically not bound to CPUS forever, | |||||
* may not occur at all. However, despite these limitations, | |||||
* observed contention rates are typically low in these cases. | |||||
* | |||||
* It is possible for a Cell to become unused when threads that | |||||
* once hashed to it terminate, as well as in the case where | |||||
* doubling the table causes no thread to hash to it under | |||||
* expanded mask. We do not try to detect or remove such cells, | |||||
* under the assumption that for long-running instances, observed | |||||
* contention levels will recur, so the cells will eventually be | |||||
* needed again; and for short-lived ones, it does not matter. | |||||
*/ | |||||
private static final long serialVersionUID = -3403386352761423917L; | |||||
/** | |||||
* Padded variant of AtomicLong supporting only raw accesses plus CAS. | |||||
* The value field is placed between pads, hoping that the JVM doesn't | |||||
* reorder them. | |||||
* | |||||
* JVM intrinsics note: It would be possible to use a release-only | |||||
* form of CAS here, if it were provided. | |||||
*/ | |||||
static final class Cell { | |||||
volatile long p0, p1, p2, p3, p4, p5, p6; | |||||
volatile long value; | |||||
volatile long q0, q1, q2, q3, q4, q5, q6; | |||||
Cell(long x) { value = x; } | |||||
final boolean cas(long cmp, long val) { | |||||
return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); | |||||
} | |||||
// Unsafe mechanics | |||||
private static final sun.misc.Unsafe UNSAFE; | |||||
private static final long valueOffset; | |||||
static { | |||||
try { | |||||
UNSAFE = getUnsafe(); | |||||
Class<?> ak = Cell.class; | |||||
valueOffset = UNSAFE.objectFieldOffset | |||||
(ak.getDeclaredField("value")); | |||||
} catch (Exception e) { | |||||
throw new Error(e); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* Holder for the thread-local hash code. The code is initially | |||||
* random, but may be set to a different value upon collisions. | |||||
*/ | |||||
static final class HashCode { | |||||
static final Random rng = new Random(); | |||||
int code; | |||||
HashCode() { | |||||
int h = rng.nextInt(); // Avoid zero to allow xorShift rehash | |||||
code = (h == 0) ? 1 : h; | |||||
} | |||||
} | |||||
/** | |||||
* The corresponding ThreadLocal class | |||||
*/ | |||||
static final class ThreadHashCode extends ThreadLocal<HashCode> { | |||||
@Override | |||||
public HashCode initialValue() { return new HashCode(); } | |||||
} | |||||
/** | |||||
* Static per-thread hash codes. Shared across all instances to | |||||
* reduce ThreadLocal pollution and because adjustments due to | |||||
* collisions in one table are likely to be appropriate for | |||||
* others. | |||||
*/ | |||||
static final ThreadHashCode threadHashCode = new ThreadHashCode(); | |||||
/** | |||||
* Number of CPUS, to place bound on table size | |||||
*/ | |||||
static final int NCPU = Runtime.getRuntime().availableProcessors(); | |||||
/** | |||||
* Table of cells. When non-null, size is a power of 2. | |||||
*/ | |||||
transient volatile Cell[] cells; | |||||
/** | |||||
* Base value, used mainly when there is no contention, but also as | |||||
* a fallback during table initialization races. Updated via CAS. | |||||
*/ | |||||
transient volatile long base; | |||||
/** | |||||
* Spinlock (locked via CAS) used when resizing and/or creating Cells. | |||||
*/ | |||||
transient volatile int busy; | |||||
/** | |||||
* Package-private default constructor | |||||
*/ | |||||
Striped64() { | |||||
} | |||||
/** | |||||
* CASes the base field. | |||||
*/ | |||||
final boolean casBase(long cmp, long val) { | |||||
return UNSAFE.compareAndSwapLong(this, baseOffset, cmp, val); | |||||
} | |||||
/** | |||||
* CASes the busy field from 0 to 1 to acquire lock. | |||||
*/ | |||||
final boolean casBusy() { | |||||
return UNSAFE.compareAndSwapInt(this, busyOffset, 0, 1); | |||||
} | |||||
/** | |||||
* Computes the function of current and new value. Subclasses | |||||
* should open-code this update function for most uses, but the | |||||
* virtualized form is needed within retryUpdate. | |||||
* | |||||
* @param currentValue the current value (of either base or a cell) | |||||
* @param newValue the argument from a user update call | |||||
* @return result of the update function | |||||
*/ | |||||
abstract long fn(long currentValue, long newValue); | |||||
/** | |||||
* Handles cases of updates involving initialization, resizing, | |||||
* creating new Cells, and/or contention. See above for | |||||
* explanation. This method suffers the usual non-modularity | |||||
* problems of optimistic retry code, relying on rechecked sets of | |||||
* reads. | |||||
* | |||||
* @param x the value | |||||
* @param hc the hash code holder | |||||
* @param wasUncontended false if CAS failed before call | |||||
*/ | |||||
final void retryUpdate(long x, HashCode hc, boolean wasUncontended) { | |||||
int h = hc.code; | |||||
boolean collide = false; // True if last slot nonempty | |||||
for (; ; ) { | |||||
Cell[] as; | |||||
Cell a; | |||||
int n; | |||||
long v; | |||||
if ((as = cells) != null && (n = as.length) > 0) { | |||||
if ((a = as[(n - 1) & h]) == null) { | |||||
if (busy == 0) { // Try to attach new Cell | |||||
Cell r = new Cell(x); // Optimistically create | |||||
if (busy == 0 && casBusy()) { | |||||
boolean created = false; | |||||
try { // Recheck under lock | |||||
Cell[] rs; | |||||
int m, j; | |||||
if ((rs = cells) != null && | |||||
(m = rs.length) > 0 && | |||||
rs[j = (m - 1) & h] == null) { | |||||
rs[j] = r; | |||||
created = true; | |||||
} | |||||
} finally { | |||||
busy = 0; | |||||
} | |||||
if (created) { break; } | |||||
continue; // Slot is now non-empty | |||||
} | |||||
} | |||||
collide = false; | |||||
} else if (!wasUncontended) // CAS already known to fail | |||||
{ | |||||
wasUncontended = true; // Continue after rehash | |||||
} else if (a.cas(v = a.value, fn(v, x))) { break; } else if (n >= NCPU || cells != as) { | |||||
collide = false; // At max size or stale | |||||
} else if (!collide) { collide = true; } else if (busy == 0 && casBusy()) { | |||||
try { | |||||
if (cells == as) { // Expand table unless stale | |||||
Cell[] rs = new Cell[n << 1]; | |||||
for (int i = 0; i < n; ++i) { rs[i] = as[i]; } | |||||
cells = rs; | |||||
} | |||||
} finally { | |||||
busy = 0; | |||||
} | |||||
collide = false; | |||||
continue; // Retry with expanded table | |||||
} | |||||
h ^= h << 13; // Rehash | |||||
h ^= h >>> 17; | |||||
h ^= h << 5; | |||||
} else if (busy == 0 && cells == as && casBusy()) { | |||||
boolean init = false; | |||||
try { // Initialize table | |||||
if (cells == as) { | |||||
Cell[] rs = new Cell[2]; | |||||
rs[h & 1] = new Cell(x); | |||||
cells = rs; | |||||
init = true; | |||||
} | |||||
} finally { | |||||
busy = 0; | |||||
} | |||||
if (init) { break; } | |||||
} else if (casBase(v = base, fn(v, x))) { | |||||
break; // Fall back on using base | |||||
} | |||||
} | |||||
hc.code = h; // Record index for next time | |||||
} | |||||
/** | |||||
* Sets base and all cells to the given value. | |||||
*/ | |||||
final void internalReset(long initialValue) { | |||||
Cell[] as = cells; | |||||
base = initialValue; | |||||
if (as != null) { | |||||
int n = as.length; | |||||
for (int i = 0; i < n; ++i) { | |||||
Cell a = as[i]; | |||||
if (a != null) { a.value = initialValue; } | |||||
} | |||||
} | |||||
} | |||||
// Unsafe mechanics | |||||
private static final sun.misc.Unsafe UNSAFE; | |||||
private static final long baseOffset; | |||||
private static final long busyOffset; | |||||
static { | |||||
try { | |||||
UNSAFE = getUnsafe(); | |||||
Class<?> sk = Striped64.class; | |||||
baseOffset = UNSAFE.objectFieldOffset | |||||
(sk.getDeclaredField("base")); | |||||
busyOffset = UNSAFE.objectFieldOffset | |||||
(sk.getDeclaredField("busy")); | |||||
} catch (Exception e) { | |||||
throw new Error(e); | |||||
} | |||||
} | |||||
/** | |||||
* Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. | |||||
* Replace with a simple call to Unsafe.getUnsafe when integrating | |||||
* into a jdk. | |||||
* | |||||
* @return a sun.misc.Unsafe | |||||
*/ | |||||
private static sun.misc.Unsafe getUnsafe() { | |||||
try { | |||||
return sun.misc.Unsafe.getUnsafe(); | |||||
} catch (SecurityException se) { | |||||
try { | |||||
return java.security.AccessController.doPrivileged | |||||
(new java.security | |||||
.PrivilegedExceptionAction<sun.misc.Unsafe>() { | |||||
@Override | |||||
public sun.misc.Unsafe run() throws Exception { | |||||
java.lang.reflect.Field f = sun.misc | |||||
.Unsafe.class.getDeclaredField("theUnsafe"); | |||||
f.setAccessible(true); | |||||
return (sun.misc.Unsafe)f.get(null); | |||||
} | |||||
}); | |||||
} catch (java.security.PrivilegedActionException e) { | |||||
throw new RuntimeException("Could not initialize intrinsics", | |||||
e.getCause()); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -15,6 +15,8 @@ | |||||
*/ | */ | ||||
package com.alibaba.csp.sentinel.slots.statistic.base; | package com.alibaba.csp.sentinel.slots.statistic.base; | ||||
import java.util.concurrent.atomic.LongAdder; | |||||
/** | /** | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
@@ -17,7 +17,7 @@ package com.alibaba.csp.sentinel.slots.statistic.data; | |||||
import com.alibaba.csp.sentinel.config.SentinelConfig; | import com.alibaba.csp.sentinel.config.SentinelConfig; | ||||
import com.alibaba.csp.sentinel.slots.statistic.MetricEvent; | import com.alibaba.csp.sentinel.slots.statistic.MetricEvent; | ||||
import com.alibaba.csp.sentinel.slots.statistic.base.LongAdder; | |||||
import java.util.concurrent.atomic.LongAdder; | |||||
/** | /** | ||||
* Represents metrics data in a period of time span. | * Represents metrics data in a period of time span. | ||||