/* * Copyright 2003-2015 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 jetbrains.mps.generator.impl.cache; import jetbrains.mps.extapi.model.GeneratableSModel; import jetbrains.mps.generator.GenerationCacheContainer; import jetbrains.mps.generator.GenerationCacheContainer.ModelCacheContainer; import jetbrains.mps.generator.IncrementalGenerationStrategy; import jetbrains.mps.generator.impl.GenerationFailureException; import jetbrains.mps.generator.impl.IncrementalGenerationHandler.IncrementalReporter; import jetbrains.mps.generator.impl.TemplateGenerator; import jetbrains.mps.generator.impl.dependencies.DependenciesBuilder; import jetbrains.mps.generator.impl.dependencies.GenerationDependencies; import jetbrains.mps.generator.impl.plan.PlanSignature; import jetbrains.mps.util.DifflibFacade; import jetbrains.mps.util.performance.IPerformanceTracer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.model.SModelReference; import java.util.Map; /** * Wraps access to optional IncrementalModelCache, facility to store/retrieve cached step models * @author Artem Tikhomirov */ public class IntermediateCacheHelper { private final IncrementalGenerationStrategy myIncrementalStrategy; private final PlanSignature myPlanSignature; private final IPerformanceTracer myPerfTrace; private IntermediateModelsCache myCache; public IntermediateCacheHelper(@NotNull IncrementalGenerationStrategy incrementalStrategy, @NotNull PlanSignature genPlanSignature, @NotNull IPerformanceTracer perfTrace) { myIncrementalStrategy = incrementalStrategy; myPlanSignature = genPlanSignature; myPerfTrace = perfTrace; } public boolean hasCache() { return myCache != null; } /** * Initialize new cache container for the model */ public void createNew(@NotNull SModel originalInput) { myCache = null; GenerationCacheContainer incrementalCacheContainer = myIncrementalStrategy.getContainer(); if (incrementalCacheContainer == null) { return; } final Map<String, String> generationHashes = myIncrementalStrategy.getModelHashes(originalInput, null); if (generationHashes == null) { return; } String currentHash = generationHashes.get(GeneratableSModel.FILE); ModelCacheContainer cacheContainer = incrementalCacheContainer.getCache(originalInput, currentHash, true); if (cacheContainer == null) { return; } myCache = new IntermediateModelsCache(cacheContainer, myPlanSignature.getSignature()); } /** * Load cache container for the model */ public void loadExisting(@NotNull SModel model, @Nullable IncrementalReporter reporter) { myCache = null; GenerationDependencies dependencies = myIncrementalStrategy.getDependencies(model); if (dependencies == null || !dependencies.isContainsIncrementalInfo()) { return; } GenerationCacheContainer incrementalCacheContainer = myIncrementalStrategy.getContainer(); if (incrementalCacheContainer == null) { if (reporter != null) { reporter.report("No container for incremental caches."); } return; } String oldHash = dependencies.getModelHash(); ModelCacheContainer cacheContainer = incrementalCacheContainer.getCache(model, oldHash, false); if (cacheContainer == null) { if (reporter != null) { reporter.report("No cache for " + model.getReference().toString() + " (" + oldHash + ")"); } return; } IntermediateModelsCache c = IntermediateModelsCache.load(cacheContainer); if (c != null && myPlanSignature.equals(c.getSignature())) { myCache = c; } else if (reporter != null) { if (c == null) { reporter.report("Caches are corrupted for " + oldHash); } else { reporter.report("Plan differs:"); for (String s : DifflibFacade.getSimpleDiff(c.getSignature(), myPlanSignature.getSignature())) { reporter.report(s); } } } } /** * Record single step into model's cache container */ // XXX TemplateGenerator has DependenciesBuilder, use it from there public void store(int majorStep, int minorStep, TemplateGenerator tg, DependenciesBuilder dependencyBuilder) throws GenerationFailureException { if (myCache == null) { return; } myPerfTrace.push("Save intermediate cache", false); final TransientModelWithMetainfo model = dependencyBuilder.create(tg.getOutputModel(), tg.getMappings()); myCache.store(majorStep, minorStep, model); myPerfTrace.pop(); } /** * Extract step data from model's cache container */ @Nullable public TransientModelWithMetainfo retrieve(int majorStep, int minorStep, @NotNull SModelReference modelReference) { if (myCache == null) { return null; } // TODO if(myMinorStep >= stepCount) copy from current input model int stepsCount = myCache.getMinorCount(majorStep); myPerfTrace.push("Load intermediate cache", false); final TransientModelWithMetainfo rv = myCache.load(majorStep, minorStep >= stepsCount ? stepsCount - 1 : minorStep, modelReference); myPerfTrace.pop(); return rv; } public boolean isStepCovered(int majorStep, int minorStep) { return myCache != null && minorStep < myCache.getMinorCount(majorStep); } public void commit() { if (myCache == null) { return; } myPerfTrace.push("Save intermediate cache", false); myCache.store(); myPerfTrace.pop(); } public void discard() { if (myCache != null) { myCache.remove(); } } }