Repository: sofastack/sofa-jraft (Java)

Issue:
关于RheaKV expect参数不支持null
```java
    public CompletableFuture<Boolean> compareAndPut(final byte[] key, final byte[] expect, final byte[] update) {
        checkState();
        Requires.requireNonNull(key, "key");
        Requires.requireNonNull(expect, "expect");
        Requires.requireNonNull(update, "update");
        final CompletableFuture<Boolean> future = new CompletableFuture<>();
        internalCompareAndPut(key, expect, update, future, this.failoverRetries, null);
        return future;
    }
```

请教一个问题，RheaKV expect参数不支持null，那如何原子的初始化值，如何保证某一个key的值从无(null)到有(update)是原子性的呢？🙏🙏


Discussion: 目前不支持 null，按道理应该支持下，欢迎提个 pr ，需要改动的地方不多
> 目前不支持 null，按道理应该支持下，欢迎提个 pr ，需要改动的地方不多

Give me this task, I'll change it  @fengjiachun 



Fix (patch):
diff --git a/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/client/DefaultRheaKVStore.java b/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/client/DefaultRheaKVStore.java
index 783bdcfaa..2ac1d2a30 100644
--- a/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/client/DefaultRheaKVStore.java
+++ b/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/client/DefaultRheaKVStore.java
@@ -1080,8 +1080,9 @@ private void internalGetAndPut(final byte[] key, final byte[] value, final Compl
     public CompletableFuture<Boolean> compareAndPut(final byte[] key, final byte[] expect, final byte[] update) {
         checkState();
         Requires.requireNonNull(key, "key");
-        Requires.requireNonNull(expect, "expect");
-        Requires.requireNonNull(update, "update");
+        if (expect == null) {
+            Requires.requireNonNull(update, "update");
+        }
         final CompletableFuture<Boolean> future = new CompletableFuture<>();
         internalCompareAndPut(key, expect, update, future, this.failoverRetries, null);
         return future;
diff --git a/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/MemoryRawKVStore.java b/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/MemoryRawKVStore.java
index 97c0abb10..40d9f773b 100644
--- a/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/MemoryRawKVStore.java
+++ b/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/MemoryRawKVStore.java
@@ -287,7 +287,11 @@ public void compareAndPut(final byte[] key, final byte[] expect, final byte[] up
         try {
             final byte[] actual = this.defaultDB.get(key);
             if (Arrays.equals(expect, actual)) {
-                this.defaultDB.put(key, update);
+                if (update == null) {
+                    this.defaultDB.remove(key);
+                } else {
+                    this.defaultDB.put(key, update);
+                }
                 setSuccess(closure, Boolean.TRUE);
             } else {
                 setSuccess(closure, Boolean.FALSE);
diff --git a/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/RocksRawKVStore.java b/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/RocksRawKVStore.java
index 60b43c1a3..60183f418 100644
--- a/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/RocksRawKVStore.java
+++ b/jraft-rheakv/rheakv-core/src/main/java/com/alipay/sofa/jraft/rhea/storage/RocksRawKVStore.java
@@ -608,7 +608,11 @@ public void compareAndPut(final byte[] key, final byte[] expect, final byte[] up
         try {
             final byte[] actual = this.db.get(key);
             if (Arrays.equals(expect, actual)) {
-                this.db.put(this.writeOptions, key, update);
+                if (update == null) {
+                    this.db.delete(this.writeOptions, key);
+                } else {
+                    this.db.put(this.writeOptions, key, update);
+                }
                 setSuccess(closure, Boolean.TRUE);
             } else {
                 setSuccess(closure, Boolean.FALSE);