protected void repairVertices()

in core/src/main/java/com/jetbrains/youtrackdb/internal/core/db/tool/GraphRepair.java [311:482]


  protected void repairVertices(
      final DatabaseSession session,
      final RepairStats stats,
      final CommandOutputListener outputListener,
      final Map<String, List<String>> options,
      final boolean checkOnly) {
    final var db = (DatabaseSessionInternal) session;
    final Metadata metadata = db.getMetadata();
    final Schema schema = metadata.getSchema();

    final var vertexClass = schema.getClass(SchemaClass.VERTEX_CLASS_NAME);
    if (vertexClass != null) {
      final var countVertices = db.countClass(vertexClass.getName());
      session.executeInTx(
          transaction -> {
            var skipVertices = 0L;
            if (options != null && options.get("-skipVertices") != null) {
              skipVertices = Long.parseLong(options.get("-skipVertices").getFirst());
            }

            message(outputListener, "Scanning " + countVertices + " vertices...\n");

            var parsedVertices = new long[]{0L};
            final var beginTime = System.currentTimeMillis();

            try (var vertexIterator = db.browseClass(vertexClass.getName())) {
              while (vertexIterator.hasNext() && !Thread.currentThread().isInterrupted()) {
                var vertex = vertexIterator.next();
                parsedVertices[0]++;
                if (skipVertices > 0 && parsedVertices[0] <= skipVertices) {
                  continue;
                }

                var vertexCorrupted = false;
                stats.scannedVertices++;
                if (eventListener != null) {
                  eventListener.onScannedVertex(vertex);
                }

                if (outputListener != null && stats.scannedVertices % 100000 == 0) {
                  var speedPerSecond =
                      (long)
                          (parsedVertices[0] / ((System.currentTimeMillis() - beginTime) / 1000.0));
                  if (speedPerSecond < 1) {
                    speedPerSecond = 1;
                  }
                  final var remaining = (countVertices - parsedVertices[0]) / speedPerSecond;

                  message(
                      outputListener,
                      "+ vertices: scanned "
                          + stats.scannedVertices
                          + ", repaired "
                          + stats.repairedVertices
                          + " (estimated remaining time "
                          + remaining
                          + " secs)\n");
                }

                if (!vertex.isVertex()) {
                  return;
                }

                for (var fieldName : vertex.getPropertyNamesInternal(false, false)) {
                  final var connection =
                      VertexEntityImpl.getConnection(
                          db.getMetadata().getSchema(), Direction.BOTH, fieldName);
                  if (connection == null) {
                    continue;
                  }

                  final var fieldValue = vertex.getPropertyInternal(fieldName);
                  if (fieldValue != null) {
                    switch (fieldValue) {
                      case Identifiable identifiable -> {
                        if (isEdgeBroken(db,
                            vertex,
                            fieldName,
                            connection.getKey(),
                            identifiable,
                            stats)) {
                          vertexCorrupted = true;
                          if (!checkOnly) {
                            vertex.setProperty(fieldName, null);
                          } else {
                            message(
                                outputListener,
                                "+ found corrupted vertex "
                                    + vertex
                                    + " the property "
                                    + fieldName
                                    + " could be removed\n");
                          }
                        }
                      }
                      case Collection<?> coll -> {

                        for (var it = coll.iterator(); it.hasNext(); ) {
                          final var o = it.next();

                          if (isEdgeBroken(db,
                              vertex, fieldName, connection.getKey(), (Identifiable) o,
                              stats)) {
                            vertexCorrupted = true;
                            if (!checkOnly) {
                              it.remove();
                            } else {
                              message(
                                  outputListener,
                                  "+ found corrupted vertex "
                                      + vertex
                                      + " the edge should be removed from property "
                                      + fieldName
                                      + " (collection)\n");
                            }
                          }
                        }
                      }
                      case LinkBag ridbag -> {
                        // In case of ridbags force save for trigger eventual conversions
                        if (ridbag.isEmpty()) {
                          vertex.removePropertyInternal(fieldName);
                        } else if (!ridbag.isEmbedded()
                            && ridbag.size()
                            < GlobalConfiguration.LINK_COLLECTION_BTREE_TO_EMBEDDED_THRESHOLD
                            .getValueAsInteger()) {
                          vertex.setDirty();
                        }
                        for (Iterator<?> it = ridbag.iterator(); it.hasNext(); ) {
                          final var o = it.next();
                          if (isEdgeBroken(db,
                              vertex, fieldName, connection.getKey(), (Identifiable) o,
                              stats)) {
                            vertexCorrupted = true;
                            if (!checkOnly) {
                              it.remove();
                            } else {
                              message(
                                  outputListener,
                                  "+ found corrupted vertex "
                                      + vertex
                                      + " the edge should be removed from property "
                                      + fieldName
                                      + " (ridbag)\n");
                            }
                          }
                        }
                      }
                      default -> {
                      }
                    }
                  }
                }

                if (vertexCorrupted) {
                  stats.repairedVertices++;
                  if (eventListener != null) {
                    eventListener.onRepairedVertex(vertex);
                  }

                  message(outputListener, "+ repaired corrupted vertex " + vertex + "\n");
                } else if (vertex.isDirty() && !checkOnly) {
                  message(outputListener, "+ optimized vertex " + vertex + "\n");

                }
              }
            }

            message(outputListener, "Scanning vertices completed\n");
          });
    }
  }