mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
optimization reimplemented: when it is evident that nothing changed, terminate make process as soon as possible
This commit is contained in:
@@ -8,12 +8,17 @@ import org.jetbrains.jps.cmdline.ProjectDescriptor;
|
||||
import org.jetbrains.jps.incremental.ModuleBuildTarget;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public class JavaModuleBuildTargetType extends BuildTargetType {
|
||||
public static final JavaModuleBuildTargetType PRODUCTION = new JavaModuleBuildTargetType("java-production", false);
|
||||
public static final JavaModuleBuildTargetType TEST = new JavaModuleBuildTargetType("java-test", true);
|
||||
public static final List<JavaModuleBuildTargetType> ALL_TYPES = Arrays.asList(PRODUCTION, TEST);
|
||||
|
||||
private boolean myTests;
|
||||
|
||||
private JavaModuleBuildTargetType(String typeId, boolean tests) {
|
||||
@@ -35,4 +40,5 @@ public class JavaModuleBuildTargetType extends BuildTargetType {
|
||||
public static JavaModuleBuildTargetType getInstance(boolean tests) {
|
||||
return tests ? TEST : PRODUCTION;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,9 @@ import org.jboss.netty.channel.Channels;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.ether.dependencyView.Callbacks;
|
||||
import org.jetbrains.jps.api.*;
|
||||
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType;
|
||||
import org.jetbrains.jps.incremental.MessageHandler;
|
||||
import org.jetbrains.jps.incremental.ModuleBuildTarget;
|
||||
import org.jetbrains.jps.incremental.Utils;
|
||||
import org.jetbrains.jps.incremental.artifacts.ArtifactSourceTimestampStorage;
|
||||
import org.jetbrains.jps.incremental.artifacts.instructions.ArtifactRootDescriptor;
|
||||
@@ -21,6 +23,7 @@ import org.jetbrains.jps.incremental.fs.FSState;
|
||||
import org.jetbrains.jps.incremental.fs.RootDescriptor;
|
||||
import org.jetbrains.jps.incremental.messages.*;
|
||||
import org.jetbrains.jps.incremental.storage.Timestamps;
|
||||
import org.jetbrains.jps.model.module.JpsModule;
|
||||
import org.jetbrains.jps.service.SharedThreadPool;
|
||||
|
||||
import java.io.*;
|
||||
@@ -138,37 +141,58 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
private void runBuild(final MessageHandler msgHandler, CanceledStatus cs) throws Throwable{
|
||||
final File dataStorageRoot = Utils.getDataStorageRoot(myProjectPath);
|
||||
if (dataStorageRoot == null) {
|
||||
msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.ERROR, "Cannot determine build data storage root for project " +
|
||||
myProjectPath));
|
||||
msgHandler.processMessage(new CompilerMessage("build", BuildMessage.Kind.ERROR, "Cannot determine build data storage root for project " + myProjectPath));
|
||||
return;
|
||||
}
|
||||
final BuildFSState fsState = new BuildFSState(false);
|
||||
if (!dataStorageRoot.exists()) {
|
||||
// invoked the very first time for this project. Force full rebuild
|
||||
myBuildType = BuildType.PROJECT_REBUILD;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!dataStorageRoot.exists()) {
|
||||
// invoked the very first time for this project. Force full rebuild
|
||||
myBuildType = BuildType.PROJECT_REBUILD;
|
||||
final DataInputStream fsStateStream = createFSDataStream(dataStorageRoot);
|
||||
|
||||
if (fsStateStream != null) {
|
||||
// optimization: check whether we can skip the build
|
||||
final boolean hasWorkToDo = fsStateStream.readBoolean();
|
||||
if (myBuildType == BuildType.MAKE && !hasWorkToDo && !containsChanges(myInitialFSDelta)) {
|
||||
updateFsStateOnDisk(dataStorageRoot, fsStateStream, myInitialFSDelta.getOrdinal());
|
||||
return;
|
||||
}
|
||||
final ProjectDescriptor pd = myBuildRunner.load(msgHandler, dataStorageRoot, fsState);
|
||||
myProjectDescriptor = pd;
|
||||
loadFsState(fsState, dataStorageRoot, myInitialFSDelta, pd);
|
||||
|
||||
// free memory
|
||||
myInitialFSDelta = null;
|
||||
// ensure events from controller are processed after FSState initialization
|
||||
myEventsProcessor.startProcessing();
|
||||
|
||||
myBuildRunner.runBuild(pd, cs, myConstantSearch, msgHandler, true, myBuildType);
|
||||
}
|
||||
finally {
|
||||
saveData(fsState, dataStorageRoot);
|
||||
|
||||
final BuildFSState fsState = new BuildFSState(false);
|
||||
final ProjectDescriptor pd = myBuildRunner.load(msgHandler, dataStorageRoot, fsState);
|
||||
myProjectDescriptor = pd;
|
||||
if (fsStateStream != null) {
|
||||
try {
|
||||
try {
|
||||
fsState.load(fsStateStream, pd);
|
||||
applyFSEvent(pd, myInitialFSDelta);
|
||||
}
|
||||
finally {
|
||||
fsStateStream.close();
|
||||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
fsState.clearAll();
|
||||
}
|
||||
}
|
||||
myLastEventOrdinal = myInitialFSDelta != null? myInitialFSDelta.getOrdinal() : 0L;
|
||||
|
||||
// free memory
|
||||
myInitialFSDelta = null;
|
||||
// ensure events from controller are processed after FSState initialization
|
||||
myEventsProcessor.startProcessing();
|
||||
|
||||
myBuildRunner.runBuild(pd, cs, myConstantSearch, msgHandler, true, myBuildType);
|
||||
saveData(fsState, dataStorageRoot);
|
||||
}
|
||||
|
||||
private void saveData(final BuildFSState fsState, File dataStorageRoot) {
|
||||
final boolean wasInterrupted = Thread.interrupted();
|
||||
try {
|
||||
saveFsState(dataStorageRoot, fsState, myLastEventOrdinal);
|
||||
saveFsState(dataStorageRoot, fsState);
|
||||
final ProjectDescriptor pd = myProjectDescriptor;
|
||||
if (pd != null) {
|
||||
pd.release();
|
||||
@@ -187,6 +211,7 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
public void run() {
|
||||
try {
|
||||
applyFSEvent(myProjectDescriptor, event);
|
||||
myLastEventOrdinal += 1;
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.error(e);
|
||||
@@ -219,93 +244,79 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pd != null) {
|
||||
final Timestamps timestamps = pd.timestamps.getStorage();
|
||||
ArtifactSourceTimestampStorage artifactTimestamps = pd.dataManager.getArtifactsBuildData().getTimestampStorage();
|
||||
final Timestamps timestamps = pd.timestamps.getStorage();
|
||||
ArtifactSourceTimestampStorage artifactTimestamps = pd.dataManager.getArtifactsBuildData().getTimestampStorage();
|
||||
|
||||
for (String deleted : event.getDeletedPathsList()) {
|
||||
final File file = new File(deleted);
|
||||
final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(null, file);
|
||||
if (rd != null) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying deleted path from fs event: " + file.getPath());
|
||||
}
|
||||
pd.fsState.registerDeleted(rd.target, file, timestamps);
|
||||
}
|
||||
else if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping deleted path: " + file.getPath());
|
||||
}
|
||||
|
||||
Collection<ArtifactRootDescriptor> descriptor = pd.getArtifactRootsIndex().getDescriptors(file);
|
||||
if (!descriptor.isEmpty()) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying deleted path from fs event to artifacts: " + file.getPath());
|
||||
}
|
||||
for (ArtifactRootDescriptor rootDescriptor : descriptor)
|
||||
pd.fsState.registerDeleted(rootDescriptor.getArtifactName(), rootDescriptor.getArtifactId(), deleted,
|
||||
artifactTimestamps);
|
||||
for (String deleted : event.getDeletedPathsList()) {
|
||||
final File file = new File(deleted);
|
||||
final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(null, file);
|
||||
if (rd != null) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying deleted path from fs event: " + file.getPath());
|
||||
}
|
||||
pd.fsState.registerDeleted(rd.target, file, timestamps);
|
||||
}
|
||||
else if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping deleted path: " + file.getPath());
|
||||
}
|
||||
for (String changed : event.getChangedPathsList()) {
|
||||
final File file = new File(changed);
|
||||
final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(null, file);
|
||||
if (rd != null) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying dirty path from fs event: " + file.getPath());
|
||||
}
|
||||
pd.fsState.markDirty(null, file, rd, timestamps);
|
||||
}
|
||||
else if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping dirty path: " + file.getPath());
|
||||
}
|
||||
|
||||
Collection<ArtifactRootDescriptor> descriptors = pd.getArtifactRootsIndex().getDescriptors(file);
|
||||
if (!descriptors.isEmpty()) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying dirty path from fs event to artifacts: " + file.getPath());
|
||||
}
|
||||
for (ArtifactRootDescriptor descriptor : descriptors) {
|
||||
pd.fsState.markDirty(descriptor, changed, artifactTimestamps);
|
||||
}
|
||||
Collection<ArtifactRootDescriptor> descriptor = pd.getArtifactRootsIndex().getDescriptors(file);
|
||||
if (!descriptor.isEmpty()) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying deleted path from fs event to artifacts: " + file.getPath());
|
||||
}
|
||||
for (ArtifactRootDescriptor rootDescriptor : descriptor)
|
||||
pd.fsState.registerDeleted(rootDescriptor.getArtifactName(), rootDescriptor.getArtifactId(), deleted,
|
||||
artifactTimestamps);
|
||||
}
|
||||
}
|
||||
for (String changed : event.getChangedPathsList()) {
|
||||
final File file = new File(changed);
|
||||
final RootDescriptor rd = pd.rootsIndex.getModuleAndRoot(null, file);
|
||||
if (rd != null) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying dirty path from fs event: " + file.getPath());
|
||||
}
|
||||
pd.fsState.markDirty(null, file, rd, timestamps);
|
||||
}
|
||||
else if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Skipping dirty path: " + file.getPath());
|
||||
}
|
||||
|
||||
Collection<ArtifactRootDescriptor> descriptors = pd.getArtifactRootsIndex().getDescriptors(file);
|
||||
if (!descriptors.isEmpty()) {
|
||||
if (Utils.IS_TEST_MODE) {
|
||||
LOG.info("Applying dirty path from fs event to artifacts: " + file.getPath());
|
||||
}
|
||||
for (ArtifactRootDescriptor descriptor : descriptors) {
|
||||
pd.fsState.markDirty(descriptor, changed, artifactTimestamps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myLastEventOrdinal += 1;
|
||||
}
|
||||
|
||||
private static void saveFsState(File dataStorageRoot, BuildFSState state, long lastEventOrdinal) {
|
||||
private void updateFsStateOnDisk(File dataStorageRoot, DataInputStream original, final long ordinal) {
|
||||
final File file = new File(dataStorageRoot, FS_STATE_FILE);
|
||||
try {
|
||||
final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
|
||||
final DataOutputStream out = new DataOutputStream(bytes);
|
||||
try {
|
||||
out.writeInt(FSState.VERSION);
|
||||
out.writeLong(lastEventOrdinal);
|
||||
state.save(out);
|
||||
out.writeLong(ordinal);
|
||||
out.writeBoolean(false);
|
||||
while (true) {
|
||||
final int b = original.read();
|
||||
if (b == -1) {
|
||||
break;
|
||||
}
|
||||
out.write(b);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
FileUtil.createIfDoesntExist(file);
|
||||
}
|
||||
|
||||
if (fos == null) {
|
||||
fos = new FileOutputStream(file);
|
||||
}
|
||||
try {
|
||||
fos.write(bytes.getInternalBuffer(), 0, bytes.size());
|
||||
}
|
||||
finally {
|
||||
fos.close();
|
||||
}
|
||||
|
||||
saveOnDisk(bytes, file);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
@@ -313,13 +324,74 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadFsState(final BuildFSState fsState,
|
||||
File dataStorageRoot,
|
||||
CmdlineRemoteProto.Message.ControllerMessage.FSEvent initialEvent,
|
||||
ProjectDescriptor pd) {
|
||||
boolean shouldApplyEvent = false;
|
||||
private void saveFsState(File dataStorageRoot, BuildFSState state) {
|
||||
final ProjectDescriptor pd = myProjectDescriptor;
|
||||
final File file = new File(dataStorageRoot, FS_STATE_FILE);
|
||||
try {
|
||||
final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
|
||||
final DataOutputStream out = new DataOutputStream(bytes);
|
||||
try {
|
||||
out.writeInt(FSState.VERSION);
|
||||
out.writeLong(myLastEventOrdinal);
|
||||
boolean hasWorkToDo = state.hasWorkToDo();
|
||||
if (!hasWorkToDo) {
|
||||
for (JpsModule module : pd.jpsProject.getModules()) {
|
||||
for (JavaModuleBuildTargetType type : JavaModuleBuildTargetType.ALL_TYPES) {
|
||||
ModuleBuildTarget target = new ModuleBuildTarget(module, type);
|
||||
if (!state.isInitialScanPerformed(target)) {
|
||||
hasWorkToDo = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasWorkToDo) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// todo: artifacts?
|
||||
}
|
||||
out.writeBoolean(hasWorkToDo);
|
||||
state.save(out);
|
||||
}
|
||||
finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
saveOnDisk(bytes, file);
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
FileUtil.delete(file);
|
||||
}
|
||||
}
|
||||
|
||||
private static void saveOnDisk(BufferExposingByteArrayOutputStream bytes, final File file) throws IOException {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file);
|
||||
}
|
||||
catch (FileNotFoundException e) {
|
||||
FileUtil.createIfDoesntExist(file);
|
||||
}
|
||||
|
||||
if (fos == null) {
|
||||
fos = new FileOutputStream(file);
|
||||
}
|
||||
try {
|
||||
fos.write(bytes.getInternalBuffer(), 0, bytes.size());
|
||||
}
|
||||
finally {
|
||||
fos.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DataInputStream createFSDataStream(File dataStorageRoot) {
|
||||
if (myInitialFSDelta == null) {
|
||||
// this will force FS rescan
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final File file = new File(dataStorageRoot, FS_STATE_FILE);
|
||||
final InputStream fs = new FileInputStream(file);
|
||||
byte[] bytes;
|
||||
try {
|
||||
@@ -328,39 +400,23 @@ final class BuildSession implements Runnable, CanceledStatus {
|
||||
finally {
|
||||
fs.close();
|
||||
}
|
||||
|
||||
final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
try {
|
||||
final int version = in.readInt();
|
||||
if (version == FSState.VERSION) {
|
||||
final long savedOrdinal = in.readLong();
|
||||
if (initialEvent != null && (savedOrdinal + 1L == initialEvent.getOrdinal())) {
|
||||
fsState.load(in, pd);
|
||||
myLastEventOrdinal = savedOrdinal;
|
||||
shouldApplyEvent = true;
|
||||
}
|
||||
}
|
||||
if (shouldApplyEvent) {
|
||||
applyFSEvent(pd, initialEvent);
|
||||
}
|
||||
else {
|
||||
// either the first start or some events were lost, forcing scan
|
||||
fsState.clearAll();
|
||||
myLastEventOrdinal = initialEvent != null? initialEvent.getOrdinal() : 0L;
|
||||
}
|
||||
final int version = in.readInt();
|
||||
if (version != FSState.VERSION) {
|
||||
return null;
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
final long savedOrdinal = in.readLong();
|
||||
if (savedOrdinal + 1L != myInitialFSDelta.getOrdinal()) {
|
||||
return null;
|
||||
}
|
||||
return; // successfully initialized
|
||||
return in;
|
||||
}
|
||||
catch (FileNotFoundException ignored) {
|
||||
}
|
||||
catch (Throwable e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
myLastEventOrdinal = initialEvent != null? initialEvent.getOrdinal() : 0L;
|
||||
fsState.clearAll();
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean containsChanges(CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) {
|
||||
|
||||
@@ -28,7 +28,7 @@ import java.util.*;
|
||||
* Date: 4/20/12
|
||||
*/
|
||||
public class FSState {
|
||||
public static final int VERSION = 1;
|
||||
public static final int VERSION = 2;
|
||||
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>());
|
||||
protected final Set<BuildTarget> myInitialScanPerformed = Collections.synchronizedSet(new HashSet<BuildTarget>());
|
||||
|
||||
Reference in New Issue
Block a user