Skip to content

Commit 8c4e76c

Browse files
committed
Improve substitution package handling and filter uses locally
Currently substitution packages handling can lead to a situation where the number of performed permutation increase considerably and the finding of a solution takes very long. In some cases it even times out and results in a failed resolve state. This now is improved by the following changes: When a permutation is removed from the stack, every requirement is checked if it is a substitution package and then resolve it to either external or internal case first: - if more candidates exits for this requirement a permutation is added to account for this alternative solution - now all other providers except the current one are dropped to make this a single provider as the choice can not be reverted and therefore other permutations in this path will be invalid - then it must be checked if the package resolves to an external provider in which case we need to drop the exported package capabilities of this bundle for the given package - after that all requirements are checked if they have only a single provider (what can happen independently or as part of the resolving to either external or internal) the use constraints are checked if they are in conflict with a currently selected provider and dropping such invalid choices - finally after that we check the package space consistency (that is a far more expensive check) what probably will result in more permutations created and checked until we found the best result to use
1 parent 25234a4 commit 8c4e76c

File tree

6 files changed

+405
-91
lines changed

6 files changed

+405
-91
lines changed

bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
import java.io.ByteArrayOutputStream;
2727
import java.io.DataInputStream;
2828
import java.io.DataOutputStream;
29+
import java.io.FileInputStream;
30+
import java.io.FileOutputStream;
2931
import java.io.IOException;
32+
import java.lang.reflect.Field;
3033
import java.net.URL;
3134
import java.nio.charset.StandardCharsets;
3235
import java.util.ArrayList;
@@ -1094,7 +1097,7 @@ public void testSubstitutableExports03() throws BundleException, IOException {
10941097

10951098
List<ModuleWire> providedWiresF = wiringF.getProvidedModuleWires(PackageNamespace.PACKAGE_NAMESPACE);
10961099
assertEquals("Wrong number of provided wires: " + providedWiresF, 0, providedWiresF.size());
1097-
assertSucessfulWith(report, 2, 1, 1, 1);
1100+
assertSucessfulWith(report, 2, 1, 1, 1); // TODO check why we now need MORE
10981101
}
10991102

11001103
@Test
@@ -3941,7 +3944,7 @@ public void testSubstitutionWithMoreThan2Providers() throws BundleException, IOE
39413944
modules.add(installDummyModule(manifest, manifest, container));
39423945
}
39433946
report = container.resolve(modules, true);
3944-
assertSucessfulWith(report, 15, 62, 47, 5);
3947+
assertSucessfulWith(report, 4, 75, 11, 1);
39453948
}
39463949

39473950
protected void assertSucessfulWith(ResolutionReport report, int maxProcessed, int maxSubstitution,
@@ -4370,14 +4373,14 @@ private static void assertWires(List<ModuleWire> required, List<ModuleWire>... p
43704373
@Test
43714374
public void testLocalUseConstraintViolations() throws Exception {
43724375
ResolutionReport result = resolveTestSet("set1");
4373-
assertSucessfulWith(result, 6, 20, 23, 6);
4376+
assertSucessfulWith(result, 3, 245, 7, 0);
43744377
}
43754378

43764379
@Test
43774380

43784381
public void testLocalUseConstraintViolations2() throws Exception {
43794382
ResolutionReport result = resolveTestSet("set2");
4380-
assertSucessfulWith(result, 3, 3, 1, 3);
4383+
assertSucessfulWith(result, 1, 2, 1, 0);
43814384
}
43824385

43834386
@Test
@@ -4394,17 +4397,24 @@ public void testSubstitutionPackageResolution() throws Exception {
43944397

43954398
@Test
43964399
public void testLargeSet() throws Exception {
4397-
ResolutionReport result = resolveModuleDatabaseDump("big", TimeUnit.MINUTES.toSeconds(5));
4398-
assertSucessfulWith(result, 1821, 29, 26359, 6736);
4400+
ResolutionReport result = resolveModuleDatabaseDump("big", 30, TimeUnit.SECONDS);
4401+
assertSucessfulWith(result, 1, 28, 1, 0);
43994402
}
44004403

44014404
@Test
44024405
public void testSdkSet() throws Exception {
4403-
ResolutionReport result = resolveModuleDatabaseDump("sdk202509", TimeUnit.MINUTES.toSeconds(1));
4404-
assertSucessfulWith(result, 9, 18, 1, 42);
4406+
ResolutionReport result = resolveModuleDatabaseDump("sdk202509", 10, TimeUnit.SECONDS);
4407+
assertSucessfulWith(result, 1, 17, 1, 0);
4408+
}
4409+
4410+
@Test
4411+
public void testBcSet() throws Exception {
4412+
ResolutionReport result = resolveModuleDatabaseDump("bc", 10, TimeUnit.MINUTES);
4413+
assertSucessfulWith(result, 100000, 100000, 100000, 100000);
44054414
}
44064415

4407-
private ResolutionReport resolveModuleDatabaseDump(String testSetName, long batchTimeoutSeconds) throws Exception {
4416+
private ResolutionReport resolveModuleDatabaseDump(String testSetName, long batchTimeout, TimeUnit timeoutUnit)
4417+
throws Exception {
44084418
URL entry = getBundle().getEntry("/test_files/containerTests/" + testSetName + ".state");
44094419
assertNotNull("can't find test set: " + testSetName, entry);
44104420
int maxThreads = Math.max(Runtime.getRuntime().availableProcessors() - 1, 1);
@@ -4421,7 +4431,7 @@ private ResolutionReport resolveModuleDatabaseDump(String testSetName, long batc
44214431
ScheduledExecutorService timeoutExecutor = new ScheduledThreadPoolExecutor(1);
44224432
Map<String, String> configuration = new HashMap<>();
44234433
configuration.put(EquinoxConfiguration.PROP_RESOLVER_BATCH_TIMEOUT,
4424-
Long.toString(TimeUnit.SECONDS.toMillis(batchTimeoutSeconds)));
4434+
Long.toString(timeoutUnit.toMillis(batchTimeout)));
44254435
DummyContainerAdaptor adaptor = new DummyContainerAdaptor(new DummyCollisionHook(false), configuration,
44264436
new DummyResolverHookFactory(), new DummyDebugOptions(Collections.emptyMap()));
44274437
adaptor.setResolverExecutor(executor);
@@ -4439,7 +4449,7 @@ private ResolutionReport resolveModuleDatabaseDump(String testSetName, long batc
44394449
}
44404450
}
44414451
AtomicBoolean timeout = new AtomicBoolean();
4442-
ScheduledFuture<?> watch = watchDog.schedule(() -> timeout.set(true), batchTimeoutSeconds, TimeUnit.SECONDS);
4452+
ScheduledFuture<?> watch = watchDog.schedule(() -> timeout.set(true), batchTimeout, timeoutUnit);
44434453
ResolutionReport report = container.resolve(container.getModules(), true);
44444454
watch.cancel(true);
44454455
assertFalse("Resolve operation timed out!", timeout.get());
@@ -4554,4 +4564,29 @@ private List<DummyModuleEvent> removeFirstListOfCommonEvents(List<DummyModuleEve
45544564
}
45554565
return result;
45564566
}
4567+
4568+
/**
4569+
* The main class takes a module database and compress/anonymous it by replace
4570+
* all locations with a running number
4571+
*
4572+
* @param args
4573+
* @throws Exception
4574+
*/
4575+
public static void main(String[] args) throws Exception {
4576+
DummyContainerAdaptor adaptor = new DummyContainerAdaptor(new DummyCollisionHook(false), null);
4577+
DummyModuleDatabase moduleDatabase = adaptor.getDatabase();
4578+
try (DataInputStream stream = new DataInputStream(new FileInputStream(args[0]))) {
4579+
moduleDatabase.load(stream);
4580+
}
4581+
List<Module> modules = adaptor.getContainer().getModules();
4582+
Field field = Module.class.getDeclaredField("location");
4583+
field.setAccessible(true);
4584+
int cnt = 0;
4585+
for (Module module : modules) {
4586+
field.set(module, Integer.toString(cnt++));
4587+
}
4588+
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(args[0] + ".compressed"))) {
4589+
moduleDatabase.store(out, false);
4590+
}
4591+
}
45574592
}
Binary file not shown.

bundles/org.eclipse.osgi/felix/src/org/apache/felix/resolver/Backlog.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.util.Collections;
2222
import java.util.LinkedHashMap;
23+
import java.util.List;
2324
import java.util.Map;
2425
import java.util.Map.Entry;
2526
import org.apache.felix.resolver.Candidates.FaultyResourcesReport;
@@ -57,7 +58,8 @@ public Backlog(ResolveSession session) {
5758
public Candidates getNext() {
5859
Candidates candidates;
5960
while ((candidates = session.getNextPermutation()) != null) {
60-
ResolutionError substituteError = candidates.checkSubstitutes();
61+
List<Candidates> alternatives = candidates.process(session.getLogger());
62+
alternatives.forEach(alt -> session.addPermutation(PermutationType.SUBSTITUTE, alt));
6163
FaultyResourcesReport report = candidates.getFaultyResources(Collections.emptyMap());
6264
if (!report.isMissing() || session.isCancelled()) {
6365
return candidates;

0 commit comments

Comments
 (0)