protected void repairEdges()

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");
          }
        });
  }