diff options
Diffstat (limited to 'bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/OptimizationFunction.java')
-rw-r--r-- | bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/OptimizationFunction.java | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/OptimizationFunction.java b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/OptimizationFunction.java new file mode 100644 index 000000000..55cc3811f --- /dev/null +++ b/bundles/org.eclipse.equinox.p2.director/src/org/eclipse/equinox/internal/p2/director/OptimizationFunction.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2013 Rapicorp Inc. and others. All rights reserved. This + * program and the accompanying materials are made available under the terms of + * the Eclipse Public License v1.0 which accompanies this distribution, and is + * available at http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Rapicorp, Inc. - initial API and implementation + ******************************************************************************/ +package org.eclipse.equinox.internal.p2.director; + +import java.math.BigInteger; +import java.util.*; +import java.util.Map.Entry; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.equinox.internal.p2.core.helpers.CollectionUtils; +import org.eclipse.equinox.internal.p2.director.Projector.AbstractVariable; +import org.eclipse.equinox.p2.metadata.*; +import org.eclipse.equinox.p2.query.*; +import org.sat4j.pb.tools.WeightedObject; + +public class OptimizationFunction { + + private IQueryable<IInstallableUnit> picker; + private IInstallableUnit selectionContext; + private Map<String, Map<Version, IInstallableUnit>> slice; //The IUs that have been considered to be part of the problem + private int numberOfInstalledIUs; + private IQueryable<IInstallableUnit> lastState; + private List<AbstractVariable> abstractVariables; + + // private IInstallableUnit[] alreadyExistingRoots; + // private IQueryable<IInstallableUnit> beingInstalled; + + public OptimizationFunction(IQueryable<IInstallableUnit> lastState, List<AbstractVariable> abstractVariables, IQueryable<IInstallableUnit> picker, IInstallableUnit selectionContext, Map<String, Map<Version, IInstallableUnit>> slice) { + this.lastState = lastState; + this.abstractVariables = abstractVariables; + this.picker = picker; + this.selectionContext = selectionContext; + this.slice = slice; + } + + //Create an optimization function favoring the highest version of each IU + public List<WeightedObject<? extends Object>> createOptimizationFunction(IInstallableUnit metaIu, Collection<IInstallableUnit> newRoots) { + numberOfInstalledIUs = sizeOf(lastState); + List<WeightedObject<? extends Object>> weightedObjects = new ArrayList<WeightedObject<? extends Object>>(); + + Set<IInstallableUnit> transitiveClosure; + if (newRoots.isEmpty()) { + transitiveClosure = CollectionUtils.emptySet(); + } else { + IQueryable<IInstallableUnit> queryable = new Slicer(picker, selectionContext, false).slice(newRoots.toArray(new IInstallableUnit[newRoots.size()]), new NullProgressMonitor()); + if (queryable == null) { + transitiveClosure = CollectionUtils.emptySet(); + } else { + transitiveClosure = queryable.query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).toSet(); + } + } + + Set<Entry<String, Map<Version, IInstallableUnit>>> s = slice.entrySet(); + final BigInteger POWER = BigInteger.valueOf(numberOfInstalledIUs > 0 ? numberOfInstalledIUs + 1 : 2); + + BigInteger maxWeight = POWER; + for (Entry<String, Map<Version, IInstallableUnit>> entry : s) { + List<IInstallableUnit> conflictingEntries = new ArrayList<IInstallableUnit>(entry.getValue().values()); + if (conflictingEntries.size() == 1) { + IInstallableUnit iu = conflictingEntries.get(0); + if (iu != metaIu) { + weightedObjects.add(WeightedObject.newWO(iu, POWER)); + } + continue; + } + // IUs are sorted from highest version to lowest. + Collections.sort(conflictingEntries, Collections.reverseOrder()); + BigInteger weight = POWER; + // have we already found a version that is already installed? + boolean foundInstalled = false; + // have we already found a version that is in the new roots? + boolean foundRoot = false; + for (IInstallableUnit iu : conflictingEntries) { + if (!foundRoot && isInstalled(iu) && !transitiveClosure.contains(iu)) { + foundInstalled = true; + weightedObjects.add(WeightedObject.newWO(iu, BigInteger.ONE)); + } else if (!foundInstalled && !foundRoot && isRoot(iu, newRoots)) { + foundRoot = true; + weightedObjects.add(WeightedObject.newWO(iu, BigInteger.ONE)); + } else { + weightedObjects.add(WeightedObject.newWO(iu, weight)); + } + weight = weight.multiply(POWER); + } + if (weight.compareTo(maxWeight) > 0) + maxWeight = weight; + } + + // no need to add one here, since maxWeight is strictly greater than the + // maximal weight used so far. + maxWeight = maxWeight.multiply(POWER).multiply(BigInteger.valueOf(s.size())); + + // Add the abstract variables + BigInteger abstractWeight = maxWeight.negate(); + for (AbstractVariable var : abstractVariables) { + weightedObjects.add(WeightedObject.newWO(var, abstractWeight)); + } + + maxWeight = maxWeight.multiply(POWER).add(BigInteger.ONE); + + BigInteger optionalWeight = maxWeight.negate(); + long countOptional = 1; + List<IInstallableUnit> requestedPatches = new ArrayList<IInstallableUnit>(); + Collection<IRequirement> reqs = metaIu.getRequirements(); + for (IRequirement req : reqs) { + if (req.getMin() > 0 || !req.isGreedy()) + continue; + IQueryResult<IInstallableUnit> matches = picker.query(QueryUtil.createMatchQuery(req.getMatches()), null); + for (Iterator<IInstallableUnit> iterator = matches.iterator(); iterator.hasNext();) { + IInstallableUnit match = iterator.next(); + if (match instanceof IInstallableUnitPatch) { + requestedPatches.add(match); + countOptional = countOptional + 1; + } else { + weightedObjects.add(WeightedObject.newWO(match, optionalWeight)); + } + } + } + + BigInteger patchWeight = maxWeight.multiply(POWER).multiply(BigInteger.valueOf(countOptional)).negate(); + for (Iterator<IInstallableUnit> iterator = requestedPatches.iterator(); iterator.hasNext();) { + weightedObjects.add(WeightedObject.newWO(iterator.next(), patchWeight)); + } + return weightedObjects; + } + + protected boolean isInstalled(IInstallableUnit iu) { + return !lastState.query(QueryUtil.createIUQuery(iu), null).isEmpty(); + } + + private boolean isRoot(IInstallableUnit iu, Collection<IInstallableUnit> newRoots) { + return newRoots.contains(iu); + } + + /** + * Efficiently compute the size of a queryable + */ + private int sizeOf(IQueryable<IInstallableUnit> installedIUs) { + IQueryResult<IInstallableUnit> qr = installedIUs.query(QueryUtil.createIUAnyQuery(), null); + if (qr instanceof Collector<?>) + return ((Collector<?>) qr).size(); + return qr.toUnmodifiableSet().size(); + } + +} |