blob: 05b68e3ac07ce53b6954220d765d1b9a37cbca88 [file] [log] [blame]
/*
* Copyright 2003-2010 the original author or authors.
*
* 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 org.codehaus.groovy.util;
public abstract class AbstractConcurrentMapBase {
protected static final int MAXIMUM_CAPACITY = 1 << 30;
static final int MAX_SEGMENTS = 1 << 16;
static final int RETRIES_BEFORE_LOCK = 2;
final int segmentMask;
final int segmentShift;
protected final Segment[] segments;
public AbstractConcurrentMapBase(Object segmentInfo) {
int sshift = 0;
int ssize = 1;
while (ssize < 16) {
++sshift;
ssize <<= 1;
}
segmentShift = 32 - sshift;
segmentMask = ssize - 1;
this.segments = new Segment[ssize];
int c = 512 / ssize;
if (c * ssize < 512)
++c;
int cap = 1;
while (cap < c)
cap <<= 1;
for (int i = 0; i < this.segments.length; ++i)
this.segments[i] = createSegment(segmentInfo, cap);
}
protected abstract Segment createSegment(Object segmentInfo, int cap);
protected static <K> int hash(K key) {
int h = System.identityHashCode(key);
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
public Segment segmentFor(int hash) {
return segments[(hash >>> segmentShift) & segmentMask];
}
public int fullSize() {
int count = 0;
for (int i = 0; i < segments.length; i++) {
segments[i].lock();
try {
for (int j = 0; j < segments[i].table.length; j++) {
Object o = segments[i].table [j];
if (o != null) {
if (o instanceof Entry) {
count++;
}
else {
Object arr [] = (Object[]) o;
count += arr.length;
}
}
}
}
finally {
segments[i].unlock();
}
}
return count;
}
public int size() {
int count = 0;
for (int i = 0; i < segments.length; i++) {
segments[i].lock();
try {
for (int j = 0; j < segments[i].table.length; j++) {
Object o = segments[i].table [j];
if (o != null) {
if (o instanceof Entry) {
Entry e = (Entry) o;
if (e.isValid())
count++;
}
else {
Object arr [] = (Object[]) o;
for (int k = 0; k < arr.length; k++) {
Entry info = (Entry) arr[k];
if (info != null && info.isValid())
count++;
}
}
}
}
}
finally {
segments[i].unlock();
}
}
return count;
}
public static class Segment extends LockableObject {
volatile int count;
int threshold;
protected volatile Object[] table;
protected Segment(int initialCapacity) {
setTable(new Object[initialCapacity]);
}
void setTable(Object[] newTable) {
threshold = (int) (newTable.length * 0.75f);
table = newTable;
}
void removeEntry (Entry e) {
lock ();
int newCount = count;
try {
Object [] tab = table;
int index = e.getHash() & (tab.length-1);
Object o = tab[index];
if (o != null) {
if (o instanceof Entry) {
if (o == e) {
tab [index] = null;
newCount--;
}
}
else {
Object arr [] = (Object[]) o;
Object res = null;
for (int i = 0; i < arr.length; i++) {
Entry info = (Entry) arr[i];
if (info != null) {
if(info != e) {
if (info.isValid()) {
res = put(info, res);
}
else {
newCount--;
}
}
else {
newCount--;
}
}
}
tab [index] = res;
}
count = newCount;
}
}
finally {
unlock();
}
}
void rehash() {
Object[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity >= MAXIMUM_CAPACITY)
return;
int newCount = 0;
for (int i = 0; i < oldCapacity ; i++) {
Object o = oldTable [i];
if (o != null) {
if (o instanceof Entry) {
Entry e = (Entry) o;
if (e.isValid()) {
newCount++;
}
else {
oldTable[i] = null;
}
}
else {
Object arr [] = (Object[]) o;
int localCount = 0;
for (int index = 0; index < arr.length; index++) {
Entry e = (Entry) arr[index];
if (e != null && e.isValid()) {
localCount++;
}
else {
arr [index] = null;
}
}
if (localCount == 0)
oldTable[i] = null;
else
newCount += localCount;
}
}
}
Object[] newTable = new Object[newCount+1 < threshold ? oldCapacity : oldCapacity << 1];
int sizeMask = newTable.length - 1;
newCount = 0;
for (int i = 0; i < oldCapacity ; i++) {
Object o = oldTable[i];
if (o != null) {
if (o instanceof Entry) {
Entry e = (Entry) o;
if (e.isValid()) {
int index = e.getHash() & sizeMask;
put(e, index, newTable);
newCount++;
}
}
else {
Object arr [] = (Object[]) o;
for (int j = 0; j < arr.length; j++) {
Entry e = (Entry) arr[j];
if (e != null && e.isValid()) {
int index = e.getHash() & sizeMask;
put(e, index, newTable);
newCount++;
}
}
}
}
}
threshold = (int)(newTable.length * 0.75f);
table = newTable;
count = newCount;
}
private void put(Entry ee, int index, Object[] tab) {
Object o = tab[index];
if (o != null) {
if (o instanceof Entry) {
Object arr [] = new Object [2];
arr [0] = ee;
arr [1] = (Entry) o;
tab[index] = arr;
return;
}
else {
Object arr [] = (Object[]) o;
Object newArr [] = new Object[arr.length+1];
newArr [0] = ee;
System.arraycopy(arr, 0, newArr, 1, arr.length);
tab [index] = newArr;
return;
}
}
tab[index] = ee;
}
private Object put(Entry ee, Object o) {
if (o != null) {
if (o instanceof Entry) {
Object arr [] = new Object [2];
arr [0] = ee;
arr [1] = (Entry) o;
return arr;
}
else {
Object arr [] = (Object[]) o;
Object newArr [] = new Object[arr.length+1];
newArr [0] = ee;
System.arraycopy(arr, 0, newArr, 1, arr.length);
return newArr;
}
}
return ee;
}
}
public interface Entry<V> {
V getValue();
void setValue(V value);
int getHash();
boolean isValid();
}
}