blob: 4db878623df7999ebc69f50aaf81a77ade40bffb [file] [log] [blame]
/*
* 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.compiler.impl.generic;
import com.intellij.openapi.compiler.generic.GenericCompiler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.Processor;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.KeyDescriptor;
import com.intellij.util.io.PersistentEnumerator;
import com.intellij.util.io.PersistentHashMap;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
/**
* @author nik
*/
public class GenericCompilerCache<Key, SourceState, OutputState> {
private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.generic.GenericCompilerCache");
private PersistentHashMap<KeyAndTargetData<Key>, PersistentStateData<SourceState, OutputState>> myPersistentMap;
private File myCacheFile;
private final GenericCompiler<Key, SourceState, OutputState> myCompiler;
public GenericCompilerCache(GenericCompiler<Key, SourceState, OutputState> compiler, final File compilerCacheDir) throws IOException {
myCompiler = compiler;
myCacheFile = new File(compilerCacheDir, "timestamps");
createMap();
}
private void createMap() throws IOException {
try {
myPersistentMap = new PersistentHashMap<KeyAndTargetData<Key>, PersistentStateData<SourceState,OutputState>>(myCacheFile, new SourceItemDataDescriptor(myCompiler.getItemKeyDescriptor()),
new PersistentStateDataExternalizer(myCompiler));
}
catch (PersistentEnumerator.CorruptedException e) {
FileUtil.delete(myCacheFile);
throw e;
}
}
private KeyAndTargetData<Key> getKeyAndTargetData(Key key, int target) {
return new KeyAndTargetData<Key>(target, key);
}
public void wipe() throws IOException {
try {
myPersistentMap.close();
}
catch (IOException ignored) {
}
PersistentHashMap.deleteFilesStartingWith(myCacheFile);
createMap();
}
public void close() {
try {
myPersistentMap.close();
}
catch (IOException e) {
LOG.info(e);
}
}
public void remove(int targetId, Key key) throws IOException {
myPersistentMap.remove(getKeyAndTargetData(key, targetId));
}
public PersistentStateData<SourceState, OutputState> getState(int targetId, Key key) throws IOException {
return myPersistentMap.get(getKeyAndTargetData(key, targetId));
}
public void processSources(final int targetId, final Processor<Key> processor) throws IOException {
myPersistentMap.processKeysWithExistingMapping(new Processor<KeyAndTargetData<Key>>() {
@Override
public boolean process(KeyAndTargetData<Key> data) {
return targetId == data.myTarget ? processor.process(data.myKey) : true;
}
});
}
public void putState(int targetId, @NotNull Key key, @NotNull SourceState sourceState, @NotNull OutputState outputState) throws IOException {
myPersistentMap.put(getKeyAndTargetData(key, targetId), new PersistentStateData<SourceState,OutputState>(sourceState, outputState));
}
private static class KeyAndTargetData<Key> {
public final int myTarget;
public final Key myKey;
private KeyAndTargetData(int target, Key key) {
myTarget = target;
myKey = key;
}
}
public static class PersistentStateData<SourceState, OutputState> {
@NotNull public final SourceState mySourceState;
@NotNull public final OutputState myOutputState;
private PersistentStateData(@NotNull SourceState sourceState, @NotNull OutputState outputState) {
mySourceState = sourceState;
myOutputState = outputState;
}
}
private class SourceItemDataDescriptor implements KeyDescriptor<KeyAndTargetData<Key>> {
private final KeyDescriptor<Key> myKeyDescriptor;
public SourceItemDataDescriptor(KeyDescriptor<Key> keyDescriptor) {
myKeyDescriptor = keyDescriptor;
}
@Override
public boolean isEqual(KeyAndTargetData<Key> val1, KeyAndTargetData<Key> val2) {
return val1.myTarget == val2.myTarget;
}
@Override
public int getHashCode(KeyAndTargetData<Key> value) {
return value.myTarget + 239 * myKeyDescriptor.getHashCode(value.myKey);
}
@Override
public void save(@NotNull DataOutput out, KeyAndTargetData<Key> value) throws IOException {
out.writeInt(value.myTarget);
myKeyDescriptor.save(out, value.myKey);
}
@Override
public KeyAndTargetData<Key> read(@NotNull DataInput in) throws IOException {
int target = in.readInt();
final Key item = myKeyDescriptor.read(in);
return getKeyAndTargetData(item, target);
}
}
private class PersistentStateDataExternalizer implements DataExternalizer<PersistentStateData<SourceState, OutputState>> {
private DataExternalizer<SourceState> mySourceStateExternalizer;
private DataExternalizer<OutputState> myOutputStateExternalizer;
public PersistentStateDataExternalizer(GenericCompiler<Key,SourceState,OutputState> compiler) {
mySourceStateExternalizer = compiler.getSourceStateExternalizer();
myOutputStateExternalizer = compiler.getOutputStateExternalizer();
}
@Override
public void save(@NotNull DataOutput out, PersistentStateData<SourceState, OutputState> value) throws IOException {
mySourceStateExternalizer.save(out, value.mySourceState);
myOutputStateExternalizer.save(out, value.myOutputState);
}
@Override
public PersistentStateData<SourceState, OutputState> read(@NotNull DataInput in) throws IOException {
SourceState sourceState = mySourceStateExternalizer.read(in);
OutputState outputState = myOutputStateExternalizer.read(in);
return new PersistentStateData<SourceState,OutputState>(sourceState, outputState);
}
}
}