sofastack / sofa-jraft

A production-grade java implementation of RAFT consensus algorithm.
https://www.sofastack.tech/projects/sofa-jraft/
Apache License 2.0
3.56k stars 1.14k forks source link

jdk11bug导致DefaultRheaIterator出现NullPointerException,是否考虑规避 #990

Closed lfygh closed 1 year ago

lfygh commented 1 year ago

Describe the bug

java.lang.NullPointerException
    at com.alipay.sofa.jraft.util.BytesUtil$LexicographicByteArrayComparator.compare(BytesUtil.java:118)
    at com.alipay.sofa.jraft.util.BytesUtil$LexicographicByteArrayComparator.compare(BytesUtil.java:112)
    at com.alipay.sofa.jraft.util.BytesUtil.compare(BytesUtil.java:95)
    at com.alipay.sofa.jraft.rhea.client.DefaultRheaIterator.hasNext(DefaultRheaIterator.java:61)
    at com.betalpha.barbeyond.kv.RheaKVStoreBackend$1.hasNext(RheaKVStoreBackend.java:87)

Steps to reproduce

这个bug准确来说应该是jdk的,项目中使用的是11.0.15,存在这个问题,升级到jdk17后不存在这个问题,中间哪个版本修复的未知,如找到,忘告知。具体的现象如果将iterator转化为stream时,即使DefaultRheaIterator.hasNext()返回false,还会多调用一次。

复现步骤:

Iterator<Object> iterator = new Iterator<>() {
          @Override
          public boolean hasNext() {
              System.out.println("call hasNext");
              return false;
          }
          @Override
          public Object next() {
              return new Object();
          }
      };
    Stream<Object> stream1 = StreamSupport
            .stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED), false)
            .map(obj -> {return obj;});   //这行必须

    Stream<Object> stream2 = StreamSupport
            .stream(Spliterators.spliteratorUnknownSize(stream1.iterator(), Spliterator.ORDERED), false);

    System.out.println(stream2.collect(Collectors.toList()));

结果是:

call hasNext
call hasNext
[]

将上述代码的iterator替换为DefaultRheaIterator即可复现NPE。

看下是否有必要兼容下这种情况

Minimal yet complete reproducer code (or GitHub URL to code)

Environment

fengjiachun commented 1 year ago

要兼容的,是不是 cursorKey == null 导致的 NPE?欢迎提一个 PR 来兼容

lfygh commented 1 year ago

好的,稍后提一个pr