Handle unavailable cluster nodes explicitly

This commit is contained in:
admin committed 2026-10-10 08:19:32 +02:00
1 parent 2276fee60c
commit 350611d562
3 files changed
+25 -12

No files matched your search

+17 -6
View File
@@ -400,23 +400,21 @@ final class ClusterStore implements ObjectStorage {
for (UUID id : segment.replicas()) { for (UUID id : segment.replicas()) {
int node = nodes.index(id); int node = nodes.index(id);
if (node < 0) continue; if (node < 0) continue;
try { byte[] candidate = readableReplica(node, segment);
byte[] candidate = nodes.get(node, segment.id(), segment.length(), segment.hash()); if (candidate == null) continue;
if (copy == null) copy = candidate; if (copy == null) copy = candidate;
healthy.add(id); healthy.add(id);
healthyHosts.add(nodes.faultDomain(node, testNodeDomains)); healthyHosts.add(nodes.faultDomain(node, testNodeDomains));
} catch (IOException error) { }
} }
if (copy == null) { unrecoverable++; continue; } if (copy == null) { unrecoverable++; continue; }
for (int node : PlacementPolicy.candidates(segment.id(), nodes, testNodeDomains)) { for (int node : PlacementPolicy.candidates(segment.id(), nodes, testNodeDomains)) {
UUID host = nodes.faultDomain(node, testNodeDomains); UUID host = nodes.faultDomain(node, testNodeDomains);
if (healthyHosts.contains(host)) continue; if (healthyHosts.contains(host)) continue;
try { if (repairReplica(node, segment, copy)) {
nodes.repair(node, segment.id(), copy, segment.hash());
healthy.add(nodes.node(node).id()); healthy.add(nodes.node(node).id());
healthyHosts.add(host); healthyHosts.add(host);
restored++; restored++;
} catch (IOException error) { } }
if (healthyHosts.size() == 3) break; if (healthyHosts.size() == 3) break;
} }
if (healthyHosts.size() < 3) underReplicated++; if (healthyHosts.size() < 3) underReplicated++;
@@ -439,6 +437,19 @@ final class ClusterStore implements ObjectStorage {
} catch (SQLException error) { throw databaseError(error); } } catch (SQLException error) { throw databaseError(error); }
return new RepairReport(scanned, restored, underReplicated, unrecoverable); return new RepairReport(scanned, restored, underReplicated, unrecoverable);
} }
private byte[] readableReplica(int node, Segment segment) {
try { return nodes.get(node, segment.id(), segment.length(), segment.hash()); }
catch (IOException unavailable) { return null; }
}
private boolean repairReplica(int node, Segment segment, byte[] copy) {
try {
nodes.repair(node, segment.id(), copy, segment.hash());
return true;
} catch (IOException unavailable) { return false; }
}
@Override public void close() {} @Override public void close() {}
private final class SegmentStream extends InputStream { private final class SegmentStream extends InputStream {
+7 -3
View File
@@ -74,6 +74,11 @@ final class NodeClient {
} }
} }
static NodeIdentity probeIfAvailable(URI url, String token) {
try { return probe(url, token); }
catch (IOException offline) { return null; }
}
static void validateUrl(URI url) { static void validateUrl(URI url) {
if (url == null || !"http".equals(url.getScheme()) || url.getHost() == null || if (url == null || !"http".equals(url.getScheme()) || url.getHost() == null ||
url.getPort() < 1 || url.getRawUserInfo() != null || url.getPort() < 1 || url.getRawUserInfo() != null ||
@@ -86,12 +91,11 @@ final class NodeClient {
Set<UUID> healthy = new HashSet<>(); Set<UUID> healthy = new HashSet<>();
for (int i = 0; i < nodes.size(); i++) { for (int i = 0; i < nodes.size(); i++) {
Node node = nodes.get(i); Node node = nodes.get(i);
try { NodeIdentity actual = probeIfAvailable(node.url(), token);
NodeIdentity actual = probe(node.url(), token); if (actual == null) continue;
if (actual.nodeId().equals(node.id()) && actual.hostId().equals(node.hostId())) if (actual.nodeId().equals(node.id()) && actual.hostId().equals(node.hostId()))
healthy.add(faultDomain(i, testNodeDomains)); healthy.add(faultDomain(i, testNodeDomains));
if (healthy.size() >= required) return true; if (healthy.size() >= required) return true;
} catch (IOException error) { }
} }
return false; return false;
} }
+1 -3
View File
@@ -126,9 +126,7 @@ final class NodeRegistry {
for (URI url : urls) { for (URI url : urls) {
NodeClient.Node node = stored.get(url.toString()); NodeClient.Node node = stored.get(url.toString());
if (node == null) throw new IOException("Unregistered storage node URL: " + url); if (node == null) throw new IOException("Unregistered storage node URL: " + url);
NodeIdentity actual = null; NodeIdentity actual = NodeClient.probeIfAvailable(url, token);
try { actual = NodeClient.probe(url, token); }
catch (IOException offline) { }
if (actual != null && (!actual.nodeId().equals(node.id()) || !actual.hostId().equals(node.hostId()))) if (actual != null && (!actual.nodeId().equals(node.id()) || !actual.hostId().equals(node.hostId())))
throw new IOException("Storage node identity changed at " + url); throw new IOException("Storage node identity changed at " + url);
configured.add(node); configured.add(node);