blob: dde4f12065dba703138d070859daea72f9c062a2 [file] [log] [blame]
/*
* Copyright 2000-2012 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 org.jetbrains.jps.incremental.fs;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.io.IOUtil;
import gnu.trove.TObjectLongHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.*;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.TargetTypeRegistry;
import org.jetbrains.jps.incremental.storage.Timestamps;
import org.jetbrains.jps.model.JpsModel;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.*;
/**
* @author Eugene Zhuravlev
* Date: 4/20/12
*/
public class FSState {
public static final int VERSION = 3;
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.fs.FSState");
private final Map<BuildTarget<?>, FilesDelta> myDeltas = Collections.synchronizedMap(new HashMap<BuildTarget<?>, FilesDelta>());
private final Set<BuildTarget<?>> myInitialScanPerformed = Collections.synchronizedSet(new HashSet<BuildTarget<?>>());
private final TObjectLongHashMap<File> myRegistrationStamps = new TObjectLongHashMap<File>(FileUtil.FILE_HASHING_STRATEGY);
public void save(DataOutput out) throws IOException {
MultiMap<BuildTargetType<?>, BuildTarget<?>> targetsByType = new MultiMap<BuildTargetType<?>, BuildTarget<?>>();
for (BuildTarget<?> target : myInitialScanPerformed) {
targetsByType.putValue(target.getTargetType(), target);
}
out.writeInt(targetsByType.size());
for (BuildTargetType<?> type : targetsByType.keySet()) {
IOUtil.writeString(type.getTypeId(), out);
Collection<BuildTarget<?>> targets = targetsByType.get(type);
out.writeInt(targets.size());
for (BuildTarget<?> target : targets) {
IOUtil.writeString(target.getId(), out);
getDelta(target).save(out);
}
}
}
public void load(DataInputStream in, JpsModel model, final BuildRootIndex buildRootIndex) throws IOException {
final TargetTypeRegistry registry = TargetTypeRegistry.getInstance();
int typeCount = in.readInt();
while (typeCount-- > 0) {
final String typeId = IOUtil.readString(in);
int targetCount = in.readInt();
BuildTargetType<?> type = registry.getTargetType(typeId);
BuildTargetLoader<?> loader = type != null ? type.createLoader(model) : null;
while (targetCount-- > 0) {
final String id = IOUtil.readString(in);
boolean loaded = false;
if (loader != null) {
BuildTarget<?> target = loader.createTarget(id);
if (target != null) {
getDelta(target).load(in, target, buildRootIndex);
myInitialScanPerformed.add(target);
loaded = true;
}
}
if (!loaded) {
LOG.info("Skipping unknown target (typeId=" + typeId + ", type=" + type + ", id=" + id + ")");
FilesDelta.skip(in);
}
}
}
}
public void clearAll() {
myInitialScanPerformed.clear();
myDeltas.clear();
myRegistrationStamps.clear();
}
public final void clearRecompile(final BuildRootDescriptor rd) {
getDelta(rd.getTarget()).clearRecompile(rd);
}
public boolean markDirty(@Nullable CompileContext context, final File file, final BuildRootDescriptor rd, final @Nullable Timestamps tsStorage, boolean saveEventStamp) throws IOException {
final boolean marked = getDelta(rd.getTarget()).markRecompile(rd, file);
if (marked) {
if (LOG.isDebugEnabled()) {
LOG.debug(rd.getTarget() + ": MARKED DIRTY: " + file.getPath());
}
if (saveEventStamp) {
myRegistrationStamps.put(file, System.currentTimeMillis());
}
if (tsStorage != null) {
tsStorage.removeStamp(file, rd.getTarget());
}
}
else {
if (LOG.isDebugEnabled()) {
LOG.debug(rd.getTarget() + ": NOT MARKED DIRTY: " + file.getPath());
}
}
return marked;
}
public long getEventRegistrationStamp(File file) {
return myRegistrationStamps.get(file);
}
public boolean markDirtyIfNotDeleted(@Nullable CompileContext context,
final File file,
final BuildRootDescriptor rd,
final @Nullable Timestamps tsStorage) throws IOException {
final boolean marked = getDelta(rd.getTarget()).markRecompileIfNotDeleted(rd, file);
if (marked && tsStorage != null) {
tsStorage.removeStamp(file, rd.getTarget());
}
return marked;
}
public void registerDeleted(BuildTarget<?> target, final File file, @Nullable Timestamps tsStorage) throws IOException {
registerDeleted(target, file);
if (tsStorage != null) {
tsStorage.removeStamp(file, target);
}
}
public void registerDeleted(BuildTarget<?> target, File file) {
getDelta(target).addDeleted(file);
}
public Map<BuildRootDescriptor, Set<File>> getSourcesToRecompile(@NotNull CompileContext context, BuildTarget<?> target) {
return getDelta(target).getSourcesToRecompile();
}
public void clearDeletedPaths(BuildTarget<?> target) {
final FilesDelta delta = myDeltas.get(target);
if (delta != null) {
delta.clearDeletedPaths();
}
}
public Collection<String> getAndClearDeletedPaths(BuildTarget<?> target) {
final FilesDelta delta = myDeltas.get(target);
if (delta != null) {
return delta.getAndClearDeletedPaths();
}
return Collections.emptyList();
}
@NotNull
protected final FilesDelta getDelta(BuildTarget<?> buildTarget) {
synchronized (myDeltas) {
FilesDelta delta = myDeltas.get(buildTarget);
if (delta == null) {
delta = new FilesDelta();
myDeltas.put(buildTarget, delta);
}
return delta;
}
}
public boolean hasWorkToDo(BuildTarget<?> target) {
if (!myInitialScanPerformed.contains(target)) return true;
FilesDelta delta = myDeltas.get(target);
return delta != null && delta.hasChanges();
}
public void markInitialScanPerformed(BuildTarget<?> target) {
myInitialScanPerformed.add(target);
}
public boolean isInitialScanPerformed(BuildTarget<?> target) {
return myInitialScanPerformed.contains(target);
}
}