Lines 71-77
Link Here
|
71 |
|
71 |
|
72 |
// for any module, set of known failed dependencies or problems, |
72 |
// for any module, set of known failed dependencies or problems, |
73 |
// or null if this has not been computed yet |
73 |
// or null if this has not been computed yet |
74 |
private final Map<Module,Set<Union2<Dependency,InvalidException>>> moduleProblems = new HashMap<Module,Set<Union2<Dependency,InvalidException>>>(100); |
74 |
private final Map<Module,Set<Union2<Dependency,InvalidException>>> moduleProblemsWithoutNeeds = new HashMap<Module,Set<Union2<Dependency,InvalidException>>>(100); |
|
|
75 |
private final Map<Module,Set<Union2<Dependency,InvalidException>>> moduleProblemsWithNeeds = new HashMap<Module,Set<Union2<Dependency,InvalidException>>>(100); |
75 |
|
76 |
|
76 |
// modules providing a given requires token; set may never be empty |
77 |
// modules providing a given requires token; set may never be empty |
77 |
private final Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>(25); |
78 |
private final Map<String,Set<Module>> providersOf = new HashMap<String,Set<Module>>(25); |
Lines 696-702
Link Here
|
696 |
// of "soft" problems (interdependencies between modules). |
697 |
// of "soft" problems (interdependencies between modules). |
697 |
// Also clear any "hard" problems associated with this module, as they |
698 |
// Also clear any "hard" problems associated with this module, as they |
698 |
// may now have been fixed. |
699 |
// may now have been fixed. |
699 |
moduleProblems.remove(m); |
700 |
moduleProblemsWithoutNeeds.remove(m); |
|
|
701 |
moduleProblemsWithNeeds.remove(m); |
700 |
firer.change(new ChangeFirer.Change(m, Module.PROP_PROBLEMS, null, null)); |
702 |
firer.change(new ChangeFirer.Change(m, Module.PROP_PROBLEMS, null, null)); |
701 |
clearProblemCache(); |
703 |
clearProblemCache(); |
702 |
firer.fire(); |
704 |
firer.fire(); |
Lines 833-839
Link Here
|
833 |
// Remember that there was a problem with this guy. |
835 |
// Remember that there was a problem with this guy. |
834 |
Module bad = ie.getModule(); |
836 |
Module bad = ie.getModule(); |
835 |
if (bad == null) throw new IllegalStateException("Problem with no associated module: " + ie); // NOI18N |
837 |
if (bad == null) throw new IllegalStateException("Problem with no associated module: " + ie); // NOI18N |
836 |
Set<Union2<Dependency,InvalidException>> probs = moduleProblems.get(bad); |
838 |
Set<Union2<Dependency,InvalidException>> probs = moduleProblemsWithNeeds.get(bad); |
837 |
if (probs == null) throw new IllegalStateException("Were trying to install a module that had never been checked: " + bad); // NOI18N |
839 |
if (probs == null) throw new IllegalStateException("Were trying to install a module that had never been checked: " + bad); // NOI18N |
838 |
if (! probs.isEmpty()) throw new IllegalStateException("Were trying to install a module that was known to be bad: " + bad); // NOI18N |
840 |
if (! probs.isEmpty()) throw new IllegalStateException("Were trying to install a module that was known to be bad: " + bad); // NOI18N |
839 |
// Record for posterity. |
841 |
// Record for posterity. |
Lines 1104-1112
Link Here
|
1104 |
// and continue with the others, try to add them too... |
1106 |
// and continue with the others, try to add them too... |
1105 |
} |
1107 |
} |
1106 |
} |
1108 |
} |
1107 |
// XXX sometimes fails, but not reproducible in a unit test. |
|
|
1108 |
// Logic is that missingDependencies(m) should contain dep in this case. |
1109 |
// Logic is that missingDependencies(m) should contain dep in this case. |
1109 |
assert foundOne : "Should have found a nonproblematic provider of " + dep + " among " + providers + " with willEnable=" + willEnable + " mightEnable=" + mightEnable; |
1110 |
assert foundOne || dep.getType() == Dependency.TYPE_RECOMMENDS : "Should have found a nonproblematic provider of " + dep + " among " + providers + " with willEnable=" + willEnable + " mightEnable=" + mightEnable; |
1110 |
} |
1111 |
} |
1111 |
// else some other kind of dependency that does not concern us |
1112 |
// else some other kind of dependency that does not concern us |
1112 |
} |
1113 |
} |
Lines 1322-1398
Link Here
|
1322 |
// Access from Module.getProblems, q.v. |
1323 |
// Access from Module.getProblems, q.v. |
1323 |
// The probed module must not be currently enabled or fixed. |
1324 |
// The probed module must not be currently enabled or fixed. |
1324 |
Set<Union2<Dependency,InvalidException>> missingDependencies(Module probed) { |
1325 |
Set<Union2<Dependency,InvalidException>> missingDependencies(Module probed) { |
|
|
1326 |
return missingDependencies(probed, true); |
1327 |
} |
1328 |
Set<Union2<Dependency,InvalidException>> missingDependencies(Module probed, boolean withNeeds) { |
1325 |
// We need to synchronize here because though this method may be called |
1329 |
// We need to synchronize here because though this method may be called |
1326 |
// only within a read mutex, it can write to moduleProblems. Other places |
1330 |
// only within a read mutex, it can write to moduleProblems. Other places |
1327 |
// where moduleProblems are used are write-mutex only and so do not have |
1331 |
// where moduleProblems are used are write-mutex only and so do not have |
1328 |
// to worry about contention. |
1332 |
// to worry about contention. |
1329 |
synchronized (moduleProblems) { |
1333 |
synchronized (moduleProblemsWithNeeds) { |
1330 |
Set<Union2<Dependency,InvalidException>> result; |
1334 |
Map<Module,Set<Union2<Dependency,InvalidException>>> mP = (withNeeds ? moduleProblemsWithNeeds : moduleProblemsWithoutNeeds); |
1331 |
ArrayList<NeedsCheck> check = new ArrayList<NeedsCheck>(); |
1335 |
Set<Union2<Dependency,InvalidException>> probs = mP.get(probed); |
1332 |
result = _missingDependencies(probed, check); |
|
|
1333 |
LOOP: while (result.isEmpty()) { |
1334 |
for (NeedsCheck needs : check) { |
1335 |
String token = needs.dep.getName(); |
1336 |
Set<Module> providers = providersOf.get(token); |
1337 |
if (providers == null) { |
1338 |
if (needs.dep.getType() == Dependency.TYPE_NEEDS) { |
1339 |
// Nobody provides it. This dep failed. |
1340 |
result.add(Union2.<Dependency,InvalidException>createFirst(needs.dep)); |
1341 |
} else { |
1342 |
// TYPE_RECOMMENDS is ok if not present |
1343 |
assert needs.dep.getType() == Dependency.TYPE_RECOMMENDS; |
1344 |
} |
1345 |
} else { |
1346 |
// We have some possible providers. Check that at least one is good. |
1347 |
boolean foundOne = false; |
1348 |
Set<Module> possibleModules = new HashSet<Module>(); |
1349 |
for (Module other : providers) { |
1350 |
if (other.isEnabled()) { |
1351 |
foundOne = true; |
1352 |
break; |
1353 |
} |
1354 |
} |
1355 |
if (!foundOne) { |
1356 |
for (Module m : providers) { |
1357 |
ArrayList<NeedsCheck> arr = new ArrayList<NeedsCheck>(); |
1358 |
if (!_missingDependencies(m, arr).isEmpty()) { |
1359 |
continue; |
1360 |
} |
1361 |
|
1362 |
if (!arr.isEmpty()) { |
1363 |
check.addAll(arr); |
1364 |
// restart the check |
1365 |
continue LOOP; |
1366 |
} |
1367 |
} |
1368 |
|
1369 |
} |
1370 |
} |
1371 |
} |
1372 |
break LOOP; |
1373 |
} |
1374 |
return result; |
1375 |
} |
1376 |
} |
1377 |
|
1378 |
private static class NeedsCheck { |
1379 |
public final Module module; |
1380 |
public final Dependency dep; |
1381 |
public NeedsCheck(Module m, Dependency d) { |
1382 |
this.module = m; |
1383 |
this.dep = d; |
1384 |
} |
1385 |
public String toString() { |
1386 |
return "(" + module + "," + dep + ")"; // NOI18N |
1387 |
} |
1388 |
} |
1389 |
|
1390 |
private Set<Union2<Dependency,InvalidException>> _missingDependencies(Module probed, Collection<NeedsCheck> nonOrderingCheck) { |
1391 |
Set<Union2<Dependency,InvalidException>> probs = moduleProblems.get(probed); |
1392 |
if (probs == null) { |
1336 |
if (probs == null) { |
1393 |
probs = new HashSet<Union2<Dependency,InvalidException>>(8); |
1337 |
probs = new HashSet<Union2<Dependency,InvalidException>>(8); |
|
|
1338 |
if (withNeeds) { |
1339 |
probs.addAll(missingDependencies(probed, false)); |
1340 |
} |
1394 |
probs.add(PROBING_IN_PROCESS); |
1341 |
probs.add(PROBING_IN_PROCESS); |
1395 |
moduleProblems.put(probed, probs); |
1342 |
mP.put(probed, probs); |
1396 |
for (Dependency dep : probed.getDependenciesArray()) { |
1343 |
for (Dependency dep : probed.getDependenciesArray()) { |
1397 |
if (dep.getType() == Dependency.TYPE_PACKAGE) { |
1344 |
if (dep.getType() == Dependency.TYPE_PACKAGE) { |
1398 |
// Can't check it in advance. Assume it is OK; if not |
1345 |
// Can't check it in advance. Assume it is OK; if not |
Lines 1457-1463
Link Here
|
1457 |
if (! other.isEnabled()) { |
1404 |
if (! other.isEnabled()) { |
1458 |
// Need to make sure the other one is not missing anything either. |
1405 |
// Need to make sure the other one is not missing anything either. |
1459 |
// Nor that it depends (directly on indirectly) on this one. |
1406 |
// Nor that it depends (directly on indirectly) on this one. |
1460 |
if (! _missingDependencies(other, nonOrderingCheck).isEmpty()) { |
1407 |
if ((!withNeeds && !missingDependencies(other, false).isEmpty()) || |
|
|
1408 |
(withNeeds && !isAlmostEmpty(missingDependencies(other, true)))) { |
1461 |
// This is a little subtle. Either the other module had real |
1409 |
// This is a little subtle. Either the other module had real |
1462 |
// problems, in which case our dependency on it is not legit. |
1410 |
// problems, in which case our dependency on it is not legit. |
1463 |
// Or, the other actually depends cyclically on this one. In |
1411 |
// Or, the other actually depends cyclically on this one. In |
Lines 1476-1482
Link Here
|
1476 |
// on it if we need it. |
1424 |
// on it if we need it. |
1477 |
} |
1425 |
} |
1478 |
// Already-installed modules are of course fine. |
1426 |
// Already-installed modules are of course fine. |
1479 |
} else if (dep.getType() == Dependency.TYPE_REQUIRES) { |
1427 |
} else if (dep.getType() == Dependency.TYPE_REQUIRES || (withNeeds && dep.getType() == Dependency.TYPE_NEEDS)) { |
1480 |
// Works much like a regular module dependency. However it only |
1428 |
// Works much like a regular module dependency. However it only |
1481 |
// fails if there are no satisfying modules with no problems. |
1429 |
// fails if there are no satisfying modules with no problems. |
1482 |
String token = dep.getName(); |
1430 |
String token = dep.getName(); |
Lines 1488-1497
Link Here
|
1488 |
// We have some possible providers. Check that at least one is good. |
1436 |
// We have some possible providers. Check that at least one is good. |
1489 |
boolean foundOne = false; |
1437 |
boolean foundOne = false; |
1490 |
for (Module other : providers) { |
1438 |
for (Module other : providers) { |
|
|
1439 |
if (foundOne) { |
1440 |
break; |
1441 |
} |
1491 |
if (other.isEnabled()) { |
1442 |
if (other.isEnabled()) { |
1492 |
foundOne = true; |
1443 |
foundOne = true; |
1493 |
} else { |
1444 |
} else { |
1494 |
if (_missingDependencies(other, nonOrderingCheck).isEmpty()) { |
1445 |
if ((!withNeeds && missingDependencies(other, false).isEmpty()) || |
|
|
1446 |
(withNeeds && isAlmostEmpty(missingDependencies(other, true)))) { |
1495 |
// See comment above for regular module deps |
1447 |
// See comment above for regular module deps |
1496 |
// re. use of PROBING_IN_PROCESS. |
1448 |
// re. use of PROBING_IN_PROCESS. |
1497 |
foundOne = true; |
1449 |
foundOne = true; |
Lines 1503-1512
Link Here
|
1503 |
probs.add(Union2.<Dependency,InvalidException>createFirst(dep)); |
1455 |
probs.add(Union2.<Dependency,InvalidException>createFirst(dep)); |
1504 |
} |
1456 |
} |
1505 |
} |
1457 |
} |
1506 |
} else if (dep.getType() == Dependency.TYPE_NEEDS || dep.getType() == Dependency.TYPE_RECOMMENDS) { |
1458 |
} else if (dep.getType() == Dependency.TYPE_JAVA) { |
1507 |
nonOrderingCheck.add(new NeedsCheck(probed, dep)); |
|
|
1508 |
} else { |
1509 |
assert dep.getType() == Dependency.TYPE_JAVA; |
1510 |
// Java dependency. Fixed for whole VM session, safe to check once and keep. |
1459 |
// Java dependency. Fixed for whole VM session, safe to check once and keep. |
1511 |
if (! Util.checkJavaDependency(dep)) { |
1460 |
if (! Util.checkJavaDependency(dep)) { |
1512 |
// Bad. |
1461 |
// Bad. |
Lines 1517-1522
Link Here
|
1517 |
probs.remove(PROBING_IN_PROCESS); |
1466 |
probs.remove(PROBING_IN_PROCESS); |
1518 |
} |
1467 |
} |
1519 |
return probs; |
1468 |
return probs; |
|
|
1469 |
} |
1470 |
} |
1471 |
private static boolean isAlmostEmpty(Set<Union2<Dependency,InvalidException>> probs) { |
1472 |
return probs.isEmpty() || probs.equals(Collections.singleton(PROBING_IN_PROCESS)); |
1520 |
} |
1473 |
} |
1521 |
|
1474 |
|
1522 |
/** Forget about any possible "soft" problems there might have been. |
1475 |
/** Forget about any possible "soft" problems there might have been. |
Lines 1530-1536
Link Here
|
1530 |
* return a different result). |
1483 |
* return a different result). |
1531 |
*/ |
1484 |
*/ |
1532 |
private void clearProblemCache() { |
1485 |
private void clearProblemCache() { |
1533 |
Iterator<Map.Entry<Module,Set<Union2<Dependency,InvalidException>>>> it = moduleProblems.entrySet().iterator(); |
1486 |
clearProblemCache(moduleProblemsWithoutNeeds); |
|
|
1487 |
clearProblemCache(moduleProblemsWithNeeds); |
1488 |
} |
1489 |
private void clearProblemCache(Map<Module,Set<Union2<Dependency,InvalidException>>> mP) { |
1490 |
Iterator<Map.Entry<Module,Set<Union2<Dependency,InvalidException>>>> it = mP.entrySet().iterator(); |
1534 |
while (it.hasNext()) { |
1491 |
while (it.hasNext()) { |
1535 |
Map.Entry<Module,Set<Union2<Dependency,InvalidException>>> entry = it.next(); |
1492 |
Map.Entry<Module,Set<Union2<Dependency,InvalidException>>> entry = it.next(); |
1536 |
Module m = entry.getKey(); |
1493 |
Module m = entry.getKey(); |