Commit 5ba13907 authored by peter's avatar peter
Browse files

extract CachingEnumerator from PersistentStringEnumerator

parent 1cd89615
Branches unavailable Tags unavailable
No related merge requests found
Showing with 198 additions and 123 deletions
+198 -123
......@@ -16,19 +16,13 @@
package com.intellij.util.io;
import com.intellij.openapi.Forceable;
import org.jetbrains.annotations.Nullable;
import java.io.Closeable;
import java.io.IOException;
/**
* Author: dmitrylomov
*/
public interface AbstractStringEnumerator extends Closeable, Forceable {
int enumerate(@Nullable String value) throws IOException;
@Nullable
String valueOf(int idx) throws IOException;
public interface AbstractStringEnumerator extends Closeable, Forceable, DataEnumerator<String> {
void markCorrupted();
}
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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.intellij.util.io;
import com.intellij.util.containers.SLRUMap;
import jsr166e.extra.SequenceLock;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
/**
* @author peter
*/
public class CachingEnumerator<Data> implements DataEnumerator<Data> {
private static final int STRIPE_POWER = 4;
private static final int STRIPE_COUNT = 1 << STRIPE_POWER;
private static final int STRIPE_MASK = STRIPE_COUNT - 1;
@SuppressWarnings("unchecked") private final SLRUMap<Integer, Integer>[] myHashcodeToIdCache = new SLRUMap[STRIPE_COUNT];
@SuppressWarnings("unchecked") private final SLRUMap<Integer, Data>[] myIdToStringCache = new SLRUMap[STRIPE_COUNT];
private final Lock[] myStripeLocks = new Lock[STRIPE_COUNT];
private final DataEnumerator<Data> myBase;
private final KeyDescriptor<Data> myDataDescriptor;
public CachingEnumerator(DataEnumerator<Data> base, KeyDescriptor<Data> dataDescriptor) {
myBase = base;
myDataDescriptor = dataDescriptor;
int protectedSize = 8192;
int probationalSize = 8192;
for(int i = 0; i < STRIPE_COUNT; ++i) {
myHashcodeToIdCache[i] = new SLRUMap<Integer, Integer>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
myIdToStringCache[i] = new SLRUMap<Integer, Data>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
myStripeLocks[i] = new SequenceLock();
}
}
public int enumerate(@Nullable Data value) throws IOException {
int valueHashCode =-1;
int stripe = -1;
if (myHashcodeToIdCache != null && value != null) {
valueHashCode = myDataDescriptor.getHashCode(value);
stripe = Math.abs(valueHashCode) & STRIPE_MASK;
Integer cachedId;
myStripeLocks[stripe].lock();
try {
cachedId = myHashcodeToIdCache[stripe].get(valueHashCode);
}
finally {
myStripeLocks[stripe].unlock();
}
if (cachedId != null) {
int stripe2 = idStripe(cachedId.intValue());
myStripeLocks[stripe2].lock();
try {
Data s = myIdToStringCache[stripe2].get(cachedId);
if (s != null && myDataDescriptor.isEqual(value, s)) return cachedId.intValue();
}
finally {
myStripeLocks[stripe2].unlock();
}
}
}
int enumerate = myBase.enumerate(value);
if (stripe != -1) {
Integer enumeratedInteger;
myStripeLocks[stripe].lock();
try {
enumeratedInteger = enumerate;
myHashcodeToIdCache[stripe].put(valueHashCode, enumeratedInteger);
} finally {
myStripeLocks[stripe].unlock();
}
int stripe2 = idStripe(enumerate);
myStripeLocks[stripe2].lock();
try {
myIdToStringCache[stripe2].put(enumeratedInteger, value);
} finally {
myStripeLocks[stripe2].unlock();
}
}
return enumerate;
}
private static int idStripe(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return Math.abs(h ^ (h >>> 7) ^ (h >>> 4)) & STRIPE_MASK;
}
@Nullable
public Data valueOf(int idx) throws IOException {
int stripe = -1;
if (myIdToStringCache != null) {
stripe = idStripe(idx);
myStripeLocks[stripe].lock();
try {
Data s = myIdToStringCache[stripe].get(idx);
if (s != null) return s;
}
finally {
myStripeLocks[stripe].unlock();
}
}
Data s = myBase.valueOf(idx);
if (stripe != -1 && s != null) {
myStripeLocks[stripe].lock();
try {
myIdToStringCache[stripe].put(idx, s);
}
finally {
myStripeLocks[stripe].unlock();
}
}
return s;
}
public void close() throws IOException {
for(int i = 0; i < myIdToStringCache.length; ++i) {
myStripeLocks[i].lock();
myIdToStringCache[i].clear();
myHashcodeToIdCache[i].clear();
myStripeLocks[i].unlock();
}
}
}
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* 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.intellij.util.io;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
/**
* @author peter
*/
public interface DataEnumerator<Data> {
int enumerate(@Nullable Data value) throws IOException;
@Nullable
Data valueOf(int idx) throws IOException;
}
......@@ -26,6 +26,7 @@ import java.io.IOException;
* Date: Dec 18, 2007
*/
public class EnumeratorStringDescriptor implements KeyDescriptor<String> {
public static final EnumeratorStringDescriptor INSTANCE = new EnumeratorStringDescriptor();
@Override
public int getHashCode(final String value) {
return value.hashCode();
......
......@@ -15,22 +15,14 @@
*/
package com.intellij.util.io;
import com.intellij.util.containers.SLRUMap;
import jsr166e.extra.SequenceLock;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.locks.Lock;
public class PersistentStringEnumerator extends PersistentEnumeratorDelegate<String> implements AbstractStringEnumerator {
private static final int STRIPE_POWER = 4;
private static final int STRIPE_COUNT = 1 << STRIPE_POWER;
private static final int STRIPE_MASK = STRIPE_COUNT - 1;
@Nullable private final SLRUMap<Integer, Integer>[] myHashcodeToIdCache;
@Nullable private final SLRUMap<Integer, String>[] myIdToStringCache;
@Nullable private final Lock[] myStripeLocks;
@Nullable private final CachingEnumerator<String> myCache;
public PersistentStringEnumerator(@NotNull final File file) throws IOException {
this(file, null);
......@@ -58,129 +50,36 @@ public class PersistentStringEnumerator extends PersistentEnumeratorDelegate<Str
final int initialSize,
boolean cacheLastMappings,
@Nullable PagedFileStorage.StorageLockContext lockContext) throws IOException {
super(file, new EnumeratorStringDescriptor(), initialSize, lockContext);
if (cacheLastMappings) {
myIdToStringCache = new SLRUMap[STRIPE_COUNT];
myHashcodeToIdCache = new SLRUMap[STRIPE_COUNT];
myStripeLocks = new Lock[STRIPE_COUNT];
int protectedSize = 8192;
int probationalSize = 8192;
super(file, EnumeratorStringDescriptor.INSTANCE, initialSize, lockContext);
myCache = cacheLastMappings ? new CachingEnumerator<String>(new DataEnumerator<String>() {
@Override
public int enumerate(@Nullable String value) throws IOException {
return PersistentStringEnumerator.super.enumerate(value);
}
for(int i = 0; i < STRIPE_COUNT; ++i) {
myHashcodeToIdCache[i] = new SLRUMap<Integer, Integer>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
myIdToStringCache[i] = new SLRUMap<Integer, String>(protectedSize / STRIPE_COUNT, probationalSize / STRIPE_COUNT);
myStripeLocks[i] = new SequenceLock();
@Nullable
@Override
public String valueOf(int idx) throws IOException {
return PersistentStringEnumerator.super.valueOf(idx);
}
} else {
myIdToStringCache = null;
myHashcodeToIdCache = null;
myStripeLocks = null;
}
}, EnumeratorStringDescriptor.INSTANCE) : null;
}
@Override
public int enumerate(@Nullable String value) throws IOException {
int valueHashCode =-1;
int stripe = -1;
if (myHashcodeToIdCache != null && value != null) {
valueHashCode = value.hashCode();
stripe = Math.abs(valueHashCode) & STRIPE_MASK;
Integer cachedId;
myStripeLocks[stripe].lock();
try {
cachedId = myHashcodeToIdCache[stripe].get(valueHashCode);
}
finally {
myStripeLocks[stripe].unlock();
}
if (cachedId != null) {
int stripe2 = idStripe(cachedId.intValue());
myStripeLocks[stripe2].lock();
try {
String s = myIdToStringCache[stripe2].get(cachedId);
if (s != null && value.equals(s)) return cachedId.intValue();
}
finally {
myStripeLocks[stripe2].unlock();
}
}
}
int enumerate = super.enumerate(value);
if (stripe != -1) {
Integer enumeratedInteger;
myStripeLocks[stripe].lock();
try {
enumeratedInteger = enumerate;
myHashcodeToIdCache[stripe].put(valueHashCode, enumeratedInteger);
} finally {
myStripeLocks[stripe].unlock();
}
int stripe2 = idStripe(enumerate);
myStripeLocks[stripe2].lock();
try {
myIdToStringCache[stripe2].put(enumeratedInteger, value);
} finally {
myStripeLocks[stripe2].unlock();
}
}
return enumerate;
}
private int idStripe(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return Math.abs(h ^ (h >>> 7) ^ (h >>> 4)) & STRIPE_MASK;
return myCache != null ? myCache.enumerate(value) : super.enumerate(value);
}
@Nullable
@Override
public String valueOf(int idx) throws IOException {
int stripe = -1;
if (myIdToStringCache != null) {
stripe = idStripe(idx);
myStripeLocks[stripe].lock();
try {
String s = myIdToStringCache[stripe].get(idx);
if (s != null) return s;
}
finally {
myStripeLocks[stripe].unlock();
}
}
String s = super.valueOf(idx);
if (stripe != -1 && s != null) {
myStripeLocks[stripe].lock();
try {
myIdToStringCache[stripe].put(idx, s);
}
finally {
myStripeLocks[stripe].unlock();
}
}
return s;
return myCache != null ? myCache.valueOf(idx) : super.valueOf(idx);
}
@Override
public void close() throws IOException {
super.close();
if (myIdToStringCache != null) {
for(int i = 0; i < myIdToStringCache.length; ++i) {
myStripeLocks[i].lock();
myIdToStringCache[i].clear();
myHashcodeToIdCache[i].clear();
myStripeLocks[i].unlock();
}
}
if (myCache != null) myCache.close();
}
@Override
......
......@@ -171,6 +171,7 @@ gruntfile
hardcoded
hardlink
hardlinks
hashcode
haxe
helvetica
holdability
......@@ -486,6 +487,7 @@ sigwaiting
sigwinch
sigxcpu
sigxfsz
slru
smallfile
smallint
soname
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment