tikv/client-java

Read is blocked by write

shiyuhang0 opened this issue · 0 comments

Bug Report

1. Describe the bug

Since TiKV v4.0.0. Read should not be blocked by writing anymore. However, client-java's batch get will be blocked by write.

2. Minimal reproduce step (Required)

/*
 * Copyright 2022 TiKV Project Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package org.tikv.txn;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;

import com.google.protobuf.ByteString;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.tikv.common.BytePairWrapper;
import org.tikv.common.ByteWrapper;
import org.tikv.common.exception.KeyException;
import org.tikv.common.util.BackOffer;
import org.tikv.common.util.ConcreteBackOffer;
import org.tikv.kvproto.Kvrpcpb.KvPair;

public class BatchGetTest extends TXNTest {

  @Test
  public void BatchGetResolveLockTest() throws Exception {
    long lockTTL = 20000L;
    String key1 = "batchGetResolveLockTestKey1";
    String key2 = "batchGetResolveLockTestKey2";
    String val1 = "val1";
    String val2 = "val2";
    String val1_update = "val1_update";
    String val2_update = "val2_update";

    // put key1 and key2
    putKV(key1, val1);
    putKV(key2, val2);

    // run 2PC background
    new Thread(
            () -> {
               long startTS = session.getTimestamp().getVersion();
              try (TwoPhaseCommitter twoPhaseCommitter =
                  new TwoPhaseCommitter(session, startTS, lockTTL)) {
                byte[] primaryKey = key1.getBytes("UTF-8");
                byte[] secondary = key2.getBytes("UTF-8");
                // prewrite primary key
                twoPhaseCommitter.prewritePrimaryKey(
                    ConcreteBackOffer.newCustomBackOff(5000),
                    primaryKey,
                    val1_update.getBytes("UTF-8"));
                List<BytePairWrapper> pairs =
                    Arrays.asList(new BytePairWrapper(secondary, val2_update.getBytes("UTF-8")));
                // prewrite secondary key
                twoPhaseCommitter.prewriteSecondaryKeys(primaryKey, pairs.iterator(), 5000);

                // get commitTS
                long commitTS = session.getTimestamp().getVersion();
                Thread.sleep(5000);
                // commit primary key
                twoPhaseCommitter.commitPrimaryKey(
                    ConcreteBackOffer.newCustomBackOff(5000), primaryKey, commitTS);
                // commit secondary key
                List<ByteWrapper> keys = Arrays.asList(new ByteWrapper(secondary));
                twoPhaseCommitter.commitSecondaryKeys(keys.iterator(), commitTS, 5000);
              } catch (Exception e) {
                KeyException keyException = (KeyException) e.getCause().getCause();
                assertNotSame("", keyException.getKeyErr().getCommitTsExpired().toString());
              }
            })
        .start();

    // wait 2PC get commitTS
    Thread.sleep(2000);
    // batch get key1 and key2
    try (KVClient kvClient = session.createKVClient()) {
      long version = session.getTimestamp().getVersion();
      ByteString k1 = ByteString.copyFromUtf8(key1);
      ByteString k2 = ByteString.copyFromUtf8(key2);

      BackOffer backOffer = ConcreteBackOffer.newCustomBackOff(5000);
      List<KvPair> kvPairs = kvClient.batchGet(backOffer, Arrays.asList(k1, k2), version);
      // Since TiKV v4.0.0 write locked key will not block read. it is supported by Min Commit
      // Timestamp
      assertEquals(ByteString.copyFromUtf8(val1), kvPairs.get(0).getValue());
      assertEquals(ByteString.copyFromUtf8(val2), kvPairs.get(1).getValue());
      // wait 2PC finish
      Thread.sleep(10000);
    }
  }
}

3. What did you see instead (Required)

This test should succeed.

4. What did you expect to see? (Required)

The batch get will fail with the below error

org.tikv.common.exception.TiKVException: locks not resolved, retry

5. What are your Java Client and TiKV versions? (Required)

  • Client Java: master 870a9fb
  • TiKV: v6.1.0