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

io.camunda.zeebe.logstreams.impl.backpressure.AppendEntryLimiter Maven / Gradle / Ivy

There is a newer version: 8.7.0-alpha2
Show newest version
/*
 * 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.1. You may not use this file
 * except in compliance with the Zeebe Community License 1.1.
 */
package io.camunda.zeebe.logstreams.impl.backpressure;

import com.netflix.concurrency.limits.limiter.AbstractLimiter;
import io.camunda.zeebe.logstreams.impl.Loggers;
import java.util.Optional;
import org.agrona.collections.Long2ObjectHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class AppendEntryLimiter extends AbstractLimiter implements AppendLimiter {

  private static final Logger LOG =
      LoggerFactory.getLogger("io.camunda.zeebe.logstreams.impl.backpressure");
  private final Long2ObjectHashMap appendedListeners = new Long2ObjectHashMap<>();
  private final AppendBackpressureMetrics metrics;

  private AppendEntryLimiter(final AppendEntryLimiterBuilder builder, final int partitionId) {
    super(builder);
    metrics = new AppendBackpressureMetrics(partitionId);
    metrics.setInflight(0);
    metrics.setNewLimit(getLimit());
  }

  public Optional acquire(final Long position) {
    if (getInflight() >= getLimit()) {
      return createRejectedListener();
    }
    final Listener listener = createListener();
    return Optional.of(listener);
  }

  private void registerListener(final long position, final Listener listener) {
    appendedListeners.put(position, listener);
  }

  public boolean tryAcquire(final Long position) {
    final Optional acquired = acquire(position);
    return acquired
        .map(
            listener -> {
              registerListener(position, listener);
              metrics.incInflight();
              return true;
            })
        .orElse(false);
  }

  public void onCommit(final long position) {
    final Listener listener = appendedListeners.remove(position);
    if (listener != null) {
      try {
        listener.onSuccess();
      } catch (final IllegalArgumentException e) {
        listener.onIgnore();
        LOG.warn(
            "Could not register request RTT (likely caused by clock problems). Consider using the 'fixed' backpressure algorithm.",
            e);
      }
      metrics.decInflight();
    } else {
      Loggers.LOGSTREAMS_LOGGER.warn(
          "We encountered an problem on releasing the acquired in flight append."
              + " There was no listener registered for the given position {}, this should not happen.",
          position);
    }
  }

  @Override
  protected void onNewLimit(final int newLimit) {
    super.onNewLimit(newLimit);
    metrics.setNewLimit(newLimit);
  }

  public static AppendEntryLimiterBuilder builder() {
    return new AppendEntryLimiterBuilder();
  }

  public static class AppendEntryLimiterBuilder
      extends AbstractLimiter.Builder {

    private int partitionId;

    @Override
    protected AppendEntryLimiterBuilder self() {
      return this;
    }

    public AppendEntryLimiterBuilder partitionId(final int partition) {
      partitionId = partition;
      return this;
    }

    public AppendEntryLimiter build() {
      return new AppendEntryLimiter(this, partitionId);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy