All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.zeebe.distributedlog.restore.log.LogReplicator Maven / Gradle / Ivy

/*
 * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
 * one or more contributor license agreements. See the NOTICE file distributed
 * with this work for additional information regarding copyright ownership.
 * Licensed under the Zeebe Community License 1.0. You may not use this file
 * except in compliance with the Zeebe Community License 1.0.
 */
package io.zeebe.distributedlog.restore.log;

import io.atomix.cluster.MemberId;
import io.zeebe.distributedlog.restore.RestoreClient;
import io.zeebe.distributedlog.restore.log.impl.DefaultLogReplicationRequest;
import io.zeebe.util.ZbLogger;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import org.slf4j.Logger;

public class LogReplicator {
  private final LogReplicationAppender appender;
  private final RestoreClient client;
  private final Executor executor;
  private final Logger logger;

  public LogReplicator(LogReplicationAppender appender, RestoreClient client, Executor executor) {
    this(appender, client, executor, new ZbLogger(LogReplicator.class));
  }

  public LogReplicator(
      LogReplicationAppender appender, RestoreClient client, Executor executor, Logger logger) {
    this.appender = appender;
    this.client = client;
    this.executor = executor;
    this.logger = logger;
  }

  public CompletableFuture replicate(MemberId server, long from, long to) {
    return replicate(server, from, to, false);
  }

  public CompletableFuture replicate(
      MemberId server, long from, long to, boolean includeFromPosition) {
    final CompletableFuture result = new CompletableFuture<>();
    replicateInternal(server, from, to, includeFromPosition, result);
    return result;
  }

  private void replicateInternal(
      MemberId server,
      long from,
      long to,
      boolean includeFromPosition,
      CompletableFuture result) {
    final LogReplicationRequest request =
        new DefaultLogReplicationRequest(from, to, includeFromPosition);
    client
        .requestLogReplication(server, request)
        .whenCompleteAsync(
            (r, e) -> {
              if (e != null) {
                logger.debug("Error replicating {} from {}", request, server, e);
                result.completeExceptionally(e);
              } else {
                if (!r.isValid()) {
                  logger.debug(
                      "Received invalid response {} when requesting {} from {}",
                      r,
                      request,
                      server);
                  result.completeExceptionally(
                      new InvalidLogReplicationResponse(server, request, r));
                  return;
                }

                if (appendEvents(server, from, to, result, r)) {
                  if (r.getToPosition() < to && r.hasMoreAvailable()) {
                    replicateInternal(server, r.getToPosition(), to, false, result);
                  } else {
                    result.complete(r.getToPosition());
                  }
                }
              }
            },
            executor);
  }

  private boolean appendEvents(
      MemberId server,
      long from,
      long to,
      CompletableFuture result,
      LogReplicationResponse response) {
    try {
      final long appendResult =
          appender.append(response.getToPosition(), response.getSerializedEvents());
      if (appendResult <= 0) {
        logger.debug("Failed to append events from {} - {} with result {}", from, to, appendResult);
        result.completeExceptionally(new FailedAppendException(server, from, to, appendResult));
      }
    } catch (RuntimeException error) {
      logger.debug("Error when appending events from {} - {}", from, to, error);
      result.completeExceptionally(error);
      return false;
    }

    return true;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy