From 2ef02e6e1c4be8b923d1128bf91be5706b3a7037 Mon Sep 17 00:00:00 2001 From: Michael Stack Date: Mon, 24 Mar 2014 23:51:31 +0000 Subject: [PATCH] HBASE-10822 Thread local addendum to HBASE-10656 Counter git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1581141 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/hadoop/hbase/util/Counter.java | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Counter.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Counter.java index 0dbb12a3645..21afd268c3f 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Counter.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Counter.java @@ -31,7 +31,6 @@ import org.apache.hadoop.classification.InterfaceStability; @InterfaceStability.Evolving public class Counter { private static final int MAX_CELLS_LENGTH = 1 << 20; - private static final int SUFFERABLE_SPIN_COUNT = 2; private static class Cell { // Pads are added around the value to avoid cache-line contention with @@ -57,18 +56,6 @@ public class Counter { return value; } - boolean addAndIsCongested(long delta) { - for(int i = 0; i < SUFFERABLE_SPIN_COUNT; i++) { - if(add(delta)) { - return false; - } - } - - while(! add(delta)) {} - - return true; - } - boolean add(long delta) { long current = value; return valueUpdater.compareAndSet(this, current, current + delta); @@ -109,16 +96,53 @@ public class Counter { } private static int hash() { - return (int) Thread.currentThread().getId(); + // The logic is borrowed from high-scale-lib's ConcurrentAutoTable. + + int h = System.identityHashCode(Thread.currentThread()); + // You would think that System.identityHashCode on the current thread + // would be a good hash fcn, but actually on SunOS 5.8 it is pretty lousy + // in the low bits. + + h ^= (h >>> 20) ^ (h >>> 12); // Bit spreader, borrowed from Doug Lea + h ^= (h >>> 7) ^ (h >>> 4); + return h; } + private static class IndexHolder { + int index = hash(); + } + + private final ThreadLocal indexHolderThreadLocal = + new ThreadLocal() { + @Override + protected IndexHolder initialValue() { + return new IndexHolder(); + } + }; + public void add(long delta) { Container container = containerRef.get(); Cell[] cells = container.cells; - int index = hash() & (cells.length - 1); - Cell cell = cells[index]; + int mask = cells.length - 1; - if(cell.addAndIsCongested(delta) && cells.length < MAX_CELLS_LENGTH && + IndexHolder indexHolder = indexHolderThreadLocal.get(); + int baseIndex = indexHolder.index; + if(cells[baseIndex & mask].add(delta)) { + return; + } + + int index = baseIndex + 1; + while(true) { + if(cells[index & mask].add(delta)) { + break; + } + index++; + } + + indexHolder.index = index; + + if(index - baseIndex >= cells.length && + cells.length < MAX_CELLS_LENGTH && container.demoted.compareAndSet(false, true)) { if(containerRef.get() == container) {