Skip to content

HDDS-14922. Define ScmInvoker#invokeRatisServer to proxy DeletedBlockLogStateManager without reflection#10013

Merged
adoroszlai merged 6 commits intoapache:masterfrom
Russole:HDDS-14922
Apr 4, 2026
Merged

HDDS-14922. Define ScmInvoker#invokeRatisServer to proxy DeletedBlockLogStateManager without reflection#10013
adoroszlai merged 6 commits intoapache:masterfrom
Russole:HDDS-14922

Conversation

@Russole
Copy link
Copy Markdown
Contributor

@Russole Russole commented Mar 31, 2026

What changes were proposed in this pull request?

  • Add invokeRatisServer(..) to ScmInvoker to centralize Ratis server invocation logic
  • Move Ratis server invocation from SCMHAInvocationHandler to ScmInvoker
  • Update SCMHAInvocationHandler to delegate DIRECT invocation to ScmInvoker
  • Add fallback to the original implementation when ScmInvoker is not available (for backward compatibility)
  • Implement the new invocation path for DeletedBlockLogStateManager

Follow-up

  • Complete the refactoring for DeletedBlockLogStateManager first; other SCM handlers will be updated in follow-up patches
  • Apply the same invocation pattern to invokeRatisClient(..) in future patches

What is the link to the Apache JIRA

https://issues.apache.org/jira/browse/HDDS-14922

How was this patch tested?

@Russole
Copy link
Copy Markdown
Contributor Author

Russole commented Mar 31, 2026

Hi @szetszwo, could you please review this PR when you have time? Thank you!

Copy link
Copy Markdown
Contributor

@szetszwo szetszwo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Russole , thanks for working on this! We should not use Proxy.newProxyInstance(..) anymore; see https://issues.apache.org/jira/secure/attachment/13081517/10013_review.patch

Comment on lines +114 to +117
if (invoker != null) {
return invoker.invokeRatisServer(
method.getName(), method.getParameterTypes(), args);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change does not help since it is after the proxy. We should do it before the proxy.

@Russole
Copy link
Copy Markdown
Contributor Author

Russole commented Apr 3, 2026

Thanks @szetszwo for the review. Updated the implementation to handle overloaded @Replicate methods and pass parameter types to invokeRatisServer, ensuring correct method resolution during Ratis invocation.
Without this, incorrect overload resolution could lead to null protobuf arguments being serialized, causing a NullPointerException in CI tests (e.g. TestScmDataDistributionFinalization).
Also updated the implementation based on the review comments.

@Russole Russole requested a review from szetszwo April 3, 2026 00:41
Copy link
Copy Markdown
Contributor

@szetszwo szetszwo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... Without this, incorrect overload resolution could lead to null ...

@Russole , Good catch on the bug!

Please see the comments inlined and also https://issues.apache.org/jira/secure/attachment/13081552/10013_review2.patch

LOG.trace("Invoking method {} on target {} with arguments {}",
method, localHandler, args);
}
Preconditions.assertNull(invoker, "invoker");
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invoker field is always null. We should remove it.

Comment on lines +86 to +88
if (invoker != null) {
return invoker.getProxy();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need the common method anymore.

  default <T> T getProxyHandler(ScmInvoker<T> invoker) {
    registerStateMachineHandler(invoker.getType(), invoker.getImpl());
    return invoker.getProxy();
  }

  default <T> T getProxyHandler(RequestType type, Class<T> intf, T impl) {
    final SCMHAInvocationHandler invocationHandler =
        new SCMHAInvocationHandler(type, impl, this);
    return intf.cast(Proxy.newProxyInstance(getClass().getClassLoader(),
        new Class<?>[] {intf}, invocationHandler));
  }

}

@Override
protected Class<?>[] getParameterTypes(String methodName) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add an enum instead:

  enum ReplicateMethod implements NameAndParameterTypes {
    addTransactionsToDB(new Class<?>[] {ArrayList.class, DeletedBlocksTransactionSummary.class}),
    removeTransactionsFromDB(new Class<?>[] {ArrayList.class, DeletedBlocksTransactionSummary.class}),
    ;

    private final Class<?>[][] parameterTypes;

    ReplicateMethod(Class<?>[] parameterTypes) {
      final Class<?>[][] types = new Class<?>[parameterTypes.length + 1][];
      for(int i = 0; i <= parameterTypes.length; ++i) {
        types[i] = Arrays.copyOf(parameterTypes, i);
      }
      this.parameterTypes = types;
    }

    @Override
    public String getName() {
      return name();
    }

    @Override
    public Class<?>[] getParameterTypes(int numArgs) {
      return parameterTypes[numArgs];
    }
  }

Comment on lines +52 to +53
Object invokeRatisServer(String methodName, Class<?>[] paramTypes,
Object[] args) throws SCMException {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add an interface:

  interface NameAndParameterTypes {
    String getName();

    Class<?>[] getParameterTypes(int numArgs);
  }
  Object invokeRatisServer(NameAndParameterTypes method, Object[] args) throws SCMException {
    try {
      final SCMRatisRequest request = SCMRatisRequest.of(
          getType(), method.getName(), method.getParameterTypes(args.length), args);

@Russole Russole requested a review from szetszwo April 4, 2026 02:28
Copy link
Copy Markdown
Contributor

@szetszwo szetszwo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 the change looks good.

@adoroszlai adoroszlai merged commit 65b938e into apache:master Apr 4, 2026
45 checks passed
@adoroszlai
Copy link
Copy Markdown
Contributor

Thanks @Russole for the patch, @szetszwo for the review.

@adoroszlai adoroszlai changed the title HDDS-14922. Define invokeRatisServer or invokeRatisClient methods HDDS-14922. Define ScmInvoker#invokeRatisServer to proxy DeletedBlockLogStateManager without reflection Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants