in core/src/main/java/com/jetbrains/youtrackdb/internal/core/db/tool/GraphRepair.java [106:309]
protected void repairEdges(
final DatabaseSession graph,
final RepairStats stats,
final CommandOutputListener outputListener,
final Map<String, List<String>> options,
final boolean checkOnly) {
final var session = (DatabaseSessionInternal) graph;
session.executeInTx(
transaction -> {
final Metadata metadata = session.getMetadata();
final Schema schema = metadata.getSchema();
final var useVertexFieldsForEdgeLabels = true; // db.isUseVertexFieldsForEdgeLabels();
final var edgeClass = schema.getClass(SchemaClass.EDGE_CLASS_NAME);
if (edgeClass != null) {
final var countEdges = session.countClass(edgeClass.getName());
var skipEdges = 0L;
if (options != null && options.get("-skipEdges") != null) {
skipEdges = Long.parseLong(options.get("-skipEdges").getFirst());
}
message(
outputListener,
"Scanning " + countEdges + " edges (skipEdges=" + skipEdges + ")...\n");
var parsedEdges = 0L;
final var beginTime = System.currentTimeMillis();
try (var edgeIterator = session.browseClass(edgeClass.getName())) {
while (edgeIterator.hasNext() && !Thread.currentThread().isInterrupted()) {
final var edge = edgeIterator.next();
if (!edge.isStatefulEdge()) {
continue;
}
final RID edgeId = edge.getIdentity();
parsedEdges++;
if (skipEdges > 0 && parsedEdges <= skipEdges) {
continue;
}
stats.scannedEdges++;
if (eventListener != null) {
eventListener.onScannedEdge(edge);
}
if (outputListener != null && stats.scannedEdges % 100000 == 0) {
var speedPerSecond =
(long) (parsedEdges / ((System.currentTimeMillis() - beginTime) / 1000.0));
if (speedPerSecond < 1) {
speedPerSecond = 1;
}
final var remaining = (countEdges - parsedEdges) / speedPerSecond;
message(
outputListener,
"+ edges: scanned "
+ stats.scannedEdges
+ ", removed "
+ stats.removedEdges
+ " (estimated remaining time "
+ remaining
+ " secs)\n");
}
var outVertexMissing = false;
var removalReason = "";
final Identifiable out = edge.asStatefulEdgeOrNull().getFrom();
if (out == null) {
outVertexMissing = true;
} else {
EntityImpl outVertex;
try {
var transaction1 = session.getActiveTransaction();
outVertex = transaction1.load(out);
} catch (RecordNotFoundException e) {
outVertex = null;
}
if (outVertex == null) {
outVertexMissing = true;
} else {
final var outFieldName =
VertexEntityImpl.getEdgeLinkFieldName(
Direction.OUT, edge.getSchemaClassName(), useVertexFieldsForEdgeLabels);
final var outEdges = outVertex.getPropertyInternal(outFieldName);
switch (outEdges) {
case null -> outVertexMissing = true;
case LinkBag rids -> {
if (!rids.contains(edgeId)) {
outVertexMissing = true;
}
}
case Collection collection -> {
if (!collection.contains(edgeId)) {
outVertexMissing = true;
}
}
case Identifiable identifiable -> {
if (identifiable.getIdentity().equals(edgeId)) {
outVertexMissing = true;
}
}
default -> {
}
}
}
}
if (outVertexMissing) {
removalReason = "outgoing vertex (" + out + ") does not contain the edge";
}
var inVertexMissing = false;
final Identifiable in = edge.asStatefulEdgeOrNull().getTo();
if (in == null) {
inVertexMissing = true;
} else {
EntityImpl inVertex;
try {
var transaction1 = session.getActiveTransaction();
inVertex = transaction1.load(in);
} catch (RecordNotFoundException e) {
inVertex = null;
}
if (inVertex == null) {
inVertexMissing = true;
} else {
final var inFieldName =
VertexEntityImpl.getEdgeLinkFieldName(
Direction.IN, edge.getSchemaClassName(), useVertexFieldsForEdgeLabels);
final var inEdges = inVertex.getPropertyInternal(inFieldName);
switch (inEdges) {
case null -> inVertexMissing = true;
case LinkBag rids -> {
if (!rids.contains(edgeId)) {
inVertexMissing = true;
}
}
case Collection collection -> {
if (!collection.contains(edgeId)) {
inVertexMissing = true;
}
}
case Identifiable identifiable -> {
if (identifiable.getIdentity().equals(edgeId)) {
inVertexMissing = true;
}
}
default -> {
}
}
}
}
if (inVertexMissing) {
if (!removalReason.isEmpty()) {
removalReason += ", ";
}
removalReason += "incoming vertex (" + in + ") does not contain the edge";
}
if (outVertexMissing || inVertexMissing) {
try {
if (!checkOnly) {
message(
outputListener,
"+ deleting corrupted edge " + edge + " because " + removalReason + "\n");
edge.delete();
} else {
message(
outputListener,
"+ found corrupted edge " + edge + " because " + removalReason + "\n");
}
stats.removedEdges++;
if (eventListener != null) {
eventListener.onRemovedEdge(edge);
}
} catch (Exception e) {
message(
outputListener,
"Error on deleting edge " + edge.getIdentity() + " (" + e.getMessage()
+ ")");
}
}
}
}
message(outputListener, "Scanning edges completed\n");
}
});
}