From eb0d8b5c4b1d0e1c43b9085a96e53e986be28120 Mon Sep 17 00:00:00 2001 From: Ziyu Shi Date: Mon, 17 Nov 2025 21:16:22 +0800 Subject: [PATCH 01/10] Hbase metrics management (#404) * add OHOperationType enum * set hbaseOpType to requests and encode to server * set hbase op type to query * fix retry for meeting ObTableNotExists when query tableGroup --- .../alipay/oceanbase/rpc/ObTableClient.java | 11 ++ .../rpc/mutation/BatchOperation.java | 7 ++ .../payload/impl/execute/OHOperationType.java | 100 ++++++++++++++++++ .../payload/impl/execute/ObHbaseRequest.java | 12 ++- .../ObTableAbstractOperationRequest.java | 9 ++ .../impl/execute/ObTableLSOpRequest.java | 13 ++- .../mutate/ObTableQueryAndMutateRequest.java | 8 +- .../query/AbstractQueryStreamResult.java | 14 ++- .../execute/query/ObTableQueryRequest.java | 9 +- .../ObTableClientQueryAsyncStreamResult.java | 1 + .../ObTableClientQueryStreamResult.java | 1 + .../table/ObTableClientLSBatchOpsImpl.java | 8 +- .../rpc/table/ObTableClientQueryImpl.java | 7 ++ 13 files changed, 188 insertions(+), 12 deletions(-) create mode 100644 src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/OHOperationType.java diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java index 9c2f27c0..c5b6218f 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java @@ -2271,6 +2271,7 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E ObTableClientQueryImpl tableQuery = new ObTableClientQueryImpl(tableName, ((ObTableQueryRequest) request).getTableQuery(), this); tableQuery.setEntityType(request.getEntityType()); + tableQuery.setHbaseOpType(request.getHbaseOpType()); return new ObClusterTableQuery(tableQuery).executeInternal(); } else if (request instanceof ObTableQueryAsyncRequest) { // TableGroup -> TableName @@ -2278,6 +2279,7 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E ObTableClientQueryImpl tableQuery = new ObTableClientQueryImpl(tableName, ((ObTableQueryAsyncRequest) request).getObTableQueryRequest().getTableQuery(), this); tableQuery.setEntityType(request.getEntityType()); + tableQuery.setHbaseOpType(request.getHbaseOpType()); ObClusterTableQuery clusterTableQuery = new ObClusterTableQuery(tableQuery); clusterTableQuery.setAllowDistributeScan(((ObTableQueryAsyncRequest) request).isAllowDistributeScan()); return clusterTableQuery.asyncExecuteInternal(); @@ -2387,6 +2389,15 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E } else { if (ex instanceof ObTableException && (((ObTableException) ex).isNeedRefreshTableEntry() || ((ObTableException) ex).isNeedRetryError())) { + if (ex instanceof ObTableNotExistException) { + String logMessage = String.format( + "exhaust retry while meet TableNotExist Exception, table name: %s, errorCode: %d", + request.getTableName(), + ((ObTableException) ex).getErrorCode() + ); + logger.warn(logMessage, ex); + throw ex; + } logger.warn( "tablename:{} partition id:{} batch ops refresh table while meet ObTableMasterChangeException, errorCode: {}", request.getTableName(), routeTabletId, ((ObTableException) ex).getErrorCode(), ex); diff --git a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java index e1ddc69e..ce5dde92 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java @@ -24,6 +24,7 @@ import com.alipay.oceanbase.rpc.get.Get; import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.OHOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.mutate.ObTableQueryAndMutate; @@ -53,6 +54,7 @@ public class BatchOperation { ObTableOperationType lastType = ObTableOperationType.INVALID; boolean isSameType = true; protected ObTableEntityType entityType = ObTableEntityType.KV; + protected OHOperationType hbaseOpType = OHOperationType.INVALID; /* * default constructor @@ -90,6 +92,10 @@ public BatchOperation setTable(String tableName) { return this; } + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } + /* * add queries */ @@ -325,6 +331,7 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { batchOps.setEntityType(entityType); batchOps.setServerCanRetry(serverCanRetry); batchOps.setNeedTabletId(needTabletId); + batchOps.setHbaseOpType(hbaseOpType); for (Object operation : operations) { if (operation instanceof CheckAndInsUp) { checkAndInsUpCnt++; diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/OHOperationType.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/OHOperationType.java new file mode 100644 index 00000000..d667ad78 --- /dev/null +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/OHOperationType.java @@ -0,0 +1,100 @@ +/*- + * #%L + * com.oceanbase:obkv-table-client + * %% + * Copyright (C) 2021 - 2025 OceanBase + * %% + * OBKV Table Client Framework is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * #L% + */ + +package com.alipay.oceanbase.rpc.protocol.payload.impl.execute; + +import java.util.*; + +public enum OHOperationType { + INVALID(0), + PUT(1), + PUT_LIST(2), + DELETE(3), + DELETE_LIST(4), + GET(5), + GET_LIST(6), + EXISTS(7), + EXISTS_LIST(8), + BATCH(9), + BATCH_CALLBACK(10), + SCAN(11), + CHECK_AND_PUT(12), + CHECK_AND_DELETE(13), + CHECK_AND_MUTATE(14), + APPEND(15), + INCREMENT(16), + INCREMENT_COLUMN_VALUE(17), + MUTATE_ROW(18); + + private final int value; + private static final Map map = new HashMap(); + + static { + for (OHOperationType type : OHOperationType.values()) { + map.put(type.value, type); + } + } + + OHOperationType(int value) { + this.value = value; + } + + public static OHOperationType valueOf(int value) { + return map.get(value); + } + + public int getValue() { + return value; + } + + public byte getByteValue() { + return (byte) value; + } + + /* + * CHECK_AND_PUT -> checkAndPut + * PUT -> put + */ + public String toCamelCase() { + String name = this.name(); + if (name == null || name.isEmpty()) { + return name; + } + + String[] parts = name.split("_"); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < parts.length; i++) { + String part = parts[i]; + if (part == null || part.isEmpty()) { + continue; + } + + if (i == 0) { + sb.append(part.toLowerCase()); + } else { + if (!part.isEmpty()) { + sb.append(Character.toUpperCase(part.charAt(0))); + if (part.length() > 1) { + sb.append(part.substring(1).toLowerCase()); + } + } + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObHbaseRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObHbaseRequest.java index 6f423694..027c40f4 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObHbaseRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObHbaseRequest.java @@ -38,7 +38,8 @@ option_flag_, op_type_, keys_, - cf_rows_); + cf_rows_, + hbase_op_type_); */ /* [k1][k2][k3]... @@ -53,6 +54,7 @@ public class ObHbaseRequest extends AbstractPayload implements Credentialable { protected ObTableOperationType opType; protected List keys = new ArrayList<>(); protected List cfRows; + protected OHOperationType hbaseOpType = OHOperationType.INVALID; public ObHbaseRequest() { this.credential = new ObBytesString(); @@ -112,6 +114,9 @@ public byte[] encode() { ObHbaseCfRows sameCfRows = cfRows.get(i); sameCfRows.encode(buf); } + + // 7. encode hbase op type, to differentiate put and put list + Serialization.encodeI8(buf, hbaseOpType.getByteValue()); if (buf.pos != buf.bytes.length) { throw new IllegalArgumentException("error in encode ObHbaseRequest (" + @@ -151,6 +156,7 @@ public long getPayloadContentSize() { for (ObHbaseCfRows cfRows : cfRows) { payLoadContentSize += cfRows.getPayloadSize(); } + payLoadContentSize += 1; // hbase_op_type_ } return payLoadContentSize; } @@ -184,6 +190,10 @@ public void setServerCanRetry(boolean canRetry) { optionFlag.setFlagServerCanRetry(canRetry); } + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } + public boolean getServerCanRetry() { return optionFlag.getFlagServerCanRetry(); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java index d037a1b4..309f7318 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java @@ -39,6 +39,7 @@ public abstract class ObTableAbstractOperationRequest extends AbstractPayload im protected ObTableOptionFlag option_flag = ObTableOptionFlag.DEFAULT; protected boolean returningAffectedEntity = false; protected boolean returningAffectedRows = false; + protected OHOperationType hbaseOpType = OHOperationType.INVALID; // for table operations, this will be INVALID(0) /* * Get payload content size. @@ -220,6 +221,14 @@ public void setNeedTabletId(boolean needTabletId) { option_flag.setNeedTabletId(needTabletId); } + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } + + public OHOperationType getHbaseOpType() { + return hbaseOpType; + } + public boolean getNeedTabletId() { return option_flag.isNeedTabletId(); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java index fdb8b89e..a8589155 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java @@ -33,13 +33,15 @@ credential_, entity_type_, consistency_level_, - ls_op_); + ls_op_, + hbase_op_type_); */ public class ObTableLSOpRequest extends AbstractPayload implements Credentialable { protected ObBytesString credential; protected ObTableEntityType entityType = ObTableEntityType.KV; protected ObTableConsistencyLevel consistencyLevel = ObTableConsistencyLevel.STRONG; private ObTableLSOperation lsOperation = null; + protected OHOperationType hbaseOpType = OHOperationType.INVALID; /* * Get pcode. @@ -70,6 +72,9 @@ public byte[] encode() { // 4. encode lsOperation lsOperation.encode(buf); + + // 5. encode hbase op type, for table operations, this will be INVALID(0) + Serialization.encodeI8(buf, hbaseOpType.getByteValue()); if (buf.pos != buf.bytes.length) { throw new IllegalArgumentException("error in encode lsOperationRequest (" + "pos:" + buf.pos + ", buf.capacity:" + buf.bytes.length + ")"); @@ -99,7 +104,7 @@ public Object decode(ByteBuf buf) { public long getPayloadContentSize() { if (payLoadContentSize == INVALID_PAYLOAD_CONTENT_SIZE) { payLoadContentSize = lsOperation.getPayloadSize() + Serialization.getNeedBytes(credential) + 1 // entityType - + 1; // consistencyLevel + + 1 /* consistencyLevel */ + 1 /* hbaseOpType */; } return payLoadContentSize; } @@ -161,6 +166,10 @@ public void setTableId(long tableId) { this.lsOperation.setTableId(tableId); } + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } + /** * Reset the cached payload content size and propagate to child objects */ diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/mutate/ObTableQueryAndMutateRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/mutate/ObTableQueryAndMutateRequest.java index f72e764e..85bd0a2c 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/mutate/ObTableQueryAndMutateRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/mutate/ObTableQueryAndMutateRequest.java @@ -35,7 +35,8 @@ entity_type_, query_and_mutate_, binlog_row_image_type_, - option_flag_); + option_flag_, + hbase_op_type_); * */ public class ObTableQueryAndMutateRequest extends ObTableAbstractOperationRequest { @@ -78,6 +79,9 @@ public byte[] encode() { idx += len; System.arraycopy(Serialization.encodeI8(option_flag.getByteValue()), 0, bytes, idx, 1); + idx += 1; + System.arraycopy(Serialization.encodeI8(hbaseOpType.getByteValue()), 0, bytes, idx, 1); + return bytes; } @@ -111,7 +115,7 @@ public long getPayloadContentSize() { if (ObGlobal.obVsnMajor() >= 4) return Serialization.getNeedBytes(credential) + Serialization.getNeedBytes(tableName) + Serialization.getNeedBytes(tableId) + 8 + 1 - + tableQueryAndMutate.getPayloadSize() + Serialization.getNeedBytes(type.getValue()) + 1; + + tableQueryAndMutate.getPayloadSize() + Serialization.getNeedBytes(type.getValue()) + 1 + 1; else return Serialization.getNeedBytes(credential) + Serialization.getNeedBytes(tableName) + Serialization.getNeedBytes(tableId) + Serialization.getNeedBytes(partitionId) diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java index 213b1f67..ffe8697f 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java @@ -30,11 +30,8 @@ import com.alipay.oceanbase.rpc.protocol.payload.Pcodes; import com.alipay.oceanbase.rpc.protocol.payload.ResultCodes; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableApiMove; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.*; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObRowKey; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableStreamRequest; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.QueryStreamResult; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.syncquery.ObTableQueryAsyncRequest; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.syncquery.ObTableQueryAsyncResult; import com.alipay.oceanbase.rpc.table.ObTable; @@ -65,6 +62,7 @@ public abstract class AbstractQueryStreamResult extends AbstractPayload implemen // global index: key is index table name (be like: __idx__) protected String indexTableName; protected ObTableEntityType entityType; + protected OHOperationType hbaseOpType = OHOperationType.INVALID; protected Map> expectant; protected List cacheProperties = new LinkedList(); protected LinkedList> cacheRows = new LinkedList>(); @@ -832,4 +830,12 @@ public ObTableClient getClient() { public void setClient(ObTableClient client) { this.client = client; } + + public OHOperationType getHbaseOpType() { + return hbaseOpType; + } + + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java index 1bdbc99b..3382b4f5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java @@ -34,7 +34,9 @@ partition_id_, entity_type_, consistency_level_, - query_ + query_, + option_flag_, + hbase_op_type_ ); * */ @@ -76,6 +78,9 @@ public byte[] encode() { idx += len; System.arraycopy(Serialization.encodeVi64(option_flag.getValue()), 0, bytes, idx, 1); + idx += 1; + System.arraycopy(Serialization.encodeI8(hbaseOpType.getByteValue()), 0, bytes, idx, 1); + return bytes; } @@ -109,7 +114,7 @@ public Object decode(ByteBuf buf) { public long getPayloadContentSize() { if (ObGlobal.obVsnMajor() >= 4) return Serialization.getNeedBytes(credential) + Serialization.getNeedBytes(tableName) - + Serialization.getNeedBytes(tableId) + 8 + 2 + tableQuery.getPayloadSize() + 1; + + Serialization.getNeedBytes(tableId) + 8 + 2 + tableQuery.getPayloadSize() + 1 + 1; else return Serialization.getNeedBytes(credential) + Serialization.getNeedBytes(tableName) + Serialization.getNeedBytes(tableId) + Serialization.getNeedBytes(partitionId) diff --git a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java index 9c2bc4ec..508adf76 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java @@ -58,6 +58,7 @@ public void init() throws Exception { request.setTableQuery(tableQuery); request.setEntityType(entityType); request.setConsistencyLevel(getReadConsistency().toObTableConsistencyLevel()); + request.setHbaseOpType(hbaseOpType); // construct async query request asyncRequest.setObTableQueryRequest(request); diff --git a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java index 3ae915f3..3dce44c2 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java @@ -50,6 +50,7 @@ protected ObTableQueryResult referToNewPartition(ObPair part request.setPartitionId(partitionId); request.setTableId(partIdWithObTable.getRight().getTableId()); request.setEntityType(entityType); + request.setHbaseOpType(hbaseOpType); if (operationTimeout > 0) { request.setTimeout(operationTimeout); } else { diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java index b5840cce..08b4c34d 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java @@ -69,7 +69,8 @@ public class ObTableClientLSBatchOpsImpl extends AbstractTableBatchOps { private boolean returningAffectedEntity = false; private boolean needAllProp = false; private boolean serverCanRetry = false; - private boolean needTabletId = false; + private boolean needTabletId = false; + protected OHOperationType hbaseOpType = OHOperationType.INVALID; private List batchOperation; /* @@ -94,6 +95,10 @@ public List getSingleOperations() { return batchOperation; } + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } + /* * Get. */ @@ -591,6 +596,7 @@ public void partitionExecute(ObTableSingleOpResult[] results, tableLsOpRequest.setTableId(tableId); tableLsOpRequest.setEntityType(entityType); tableLsOpRequest.setTimeout(operationTimeout); + tableLsOpRequest.setHbaseOpType(hbaseOpType); ObTableLSOpResult subLSOpResult; boolean needRefreshPartitionLocation = false; diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java index 64123e5d..50baca59 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java @@ -28,6 +28,7 @@ import com.alipay.oceanbase.rpc.protocol.payload.ObPayload; import com.alipay.oceanbase.rpc.protocol.payload.ResultCodes; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObRowKey; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.OHOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.aggregation.ObTableAggregationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.*; @@ -53,6 +54,7 @@ public class ObTableClientQueryImpl extends AbstractTableQueryImpl { private Row rowKey; // only used by BatchOperation private boolean allowDistributeScan = true; + private OHOperationType hbaseOpType = OHOperationType.INVALID; /* * Add aggregation. @@ -162,6 +164,7 @@ private void setCommonParams2Result(AbstractQueryStreamResult result) throws Exc result.setExpectant(partitionObTables); result.setOperationTimeout(operationTimeout); result.setReadConsistency(obTableClient.getReadConsistency()); + result.setHbaseOpType(hbaseOpType); } private abstract static class InitQueryResultCallback { @@ -445,4 +448,8 @@ public Long getPartId() { public void setAllowDistributeScan(boolean allowDistributeScan) { this.allowDistributeScan = allowDistributeScan; } + + public void setHbaseOpType(OHOperationType hbaseOpType) { + this.hbaseOpType = hbaseOpType; + } } From 81ca0894af63ad0fc24a31caf5dd8cb644b1a5d5 Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Tue, 18 Nov 2025 15:40:14 +0800 Subject: [PATCH 02/10] support weak read (#406) --- .../oceanbase/rpc/ObClusterTableBatchOps.java | 6 + .../oceanbase/rpc/ObClusterTableQuery.java | 20 + .../alipay/oceanbase/rpc/ObTableClient.java | 307 +-- .../rpc/bolt/protocol/ObTablePacketCode.java | 5 - .../rpc/bolt/transport/ObClientFuture.java | 1 - .../rpc/bolt/transport/ObTableConnection.java | 3 +- .../ObTableSessionNotExistException.java | 17 + .../com/alipay/oceanbase/rpc/get/Get.java | 32 +- .../oceanbase/rpc/location/LocationUtil.java | 461 ++-- .../rpc/location/model/ConfigServerInfo.java | 22 +- .../rpc/location/model/ObReadConsistency.java | 100 - .../rpc/location/model/ObRoutePolicy.java | 41 +- .../rpc/location/model/ObServerAddr.java | 14 + .../rpc/location/model/ObServerLdcItem.java | 20 +- .../location/model/ObServerLdcLocation.java | 19 +- .../rpc/location/model/ObServerRoute.java | 105 - .../oceanbase/rpc/location/model/OdpInfo.java | 23 +- .../rpc/location/model/ReplicaLocation.java | 7 + .../location/model/RouteTableRefresher.java | 6 - .../rpc/location/model/TableLocations.java | 12 +- .../rpc/location/model/TableRoute.java | 333 ++- .../model/partition/ObPartitionEntry.java | 59 +- .../model/partition/ObPartitionLocation.java | 67 +- .../rpc/mutation/BatchOperation.java | 34 +- .../impl/execute/ObTableConsistencyLevel.java | 10 + .../query/AbstractQueryStreamResult.java | 27 +- .../ObTableClientQueryAsyncStreamResult.java | 51 +- .../ObTableClientQueryStreamResult.java | 5 +- .../rpc/table/AbstractTableBatchOps.java | 17 + .../rpc/table/AbstractTableQuery.java | 18 +- .../rpc/table/AbstractTableQueryImpl.java | 1 - .../rpc/table/ObTableClientBatchOpsImpl.java | 68 +- .../table/ObTableClientLSBatchOpsImpl.java | 36 +- .../rpc/table/ObTableClientQueryImpl.java | 59 +- .../rpc/table/api/TableBatchOps.java | 4 + .../oceanbase/rpc/table/api/TableQuery.java | 7 +- .../rpc/threadlocal/ThreadLocalMap.java | 15 - .../rpc/ObTableClientAutoIncTest.java | 1 - .../rpc/ObTableClientCheckAndInsertTest.java | 1 - .../oceanbase/rpc/ObTableWeakReadTest.java | 2141 +++++++++++++++++ .../rpc/ObWeakReadConsistencyTest.java | 125 - .../rpc/bolt/ObTableClientTestBase.java | 2 +- .../oceanbase/rpc/bolt/ObTableTest.java | 89 - .../oceanbase/rpc/hbase/ObHTableTest.java | 228 -- .../ObTableLsOperationRequestTest.java | 30 +- .../rpc/table/ObTableConnectionTest.java | 19 +- 46 files changed, 3076 insertions(+), 1592 deletions(-) delete mode 100644 src/main/java/com/alipay/oceanbase/rpc/location/model/ObReadConsistency.java delete mode 100644 src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerRoute.java create mode 100644 src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java delete mode 100644 src/test/java/com/alipay/oceanbase/rpc/ObWeakReadConsistencyTest.java delete mode 100644 src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableTest.java delete mode 100644 src/test/java/com/alipay/oceanbase/rpc/hbase/ObHTableTest.java diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableBatchOps.java b/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableBatchOps.java index ab1c048d..e436e79b 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableBatchOps.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableBatchOps.java @@ -184,6 +184,12 @@ public void setReturnOneResult(boolean returnOneResult) { tableBatchOps.setReturnOneResult(returnOneResult); } + @Override + public void setIsWeakRead(boolean isWeakRead) { + super.setIsWeakRead(isWeakRead); + tableBatchOps.setIsWeakRead(isWeakRead); + } + void preCheck() { List operations = this.tableBatchOps.getObTableBatchOperation() .getTableOperations(); diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java index 854e7581..172f7782 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java @@ -271,6 +271,26 @@ public TableQuery setSearchText(String searchText) { return this; } + @Override + public TableQuery setReadConsistency(String readConsistency) { + // 同时设置父类和内部 tableClientQuery 的 readConsistency + super.setReadConsistency(readConsistency); + tableClientQuery.setReadConsistency(readConsistency); + return this; + } + + @Override + public String getReadConsistency() { + // 返回内部 tableClientQuery 的 readConsistency + return tableClientQuery.getReadConsistency(); + } + + @Override + public TableQuery setScanRangeColumns(String... columns) { + tableClientQuery.setScanRangeColumns(columns); + return this; + } + public void setAllowDistributeScan(boolean allowDistributeScan) { tableClientQuery.setAllowDistributeScan(allowDistributeScan); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java index c5b6218f..6f981e70 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java @@ -41,7 +41,6 @@ import com.alipay.oceanbase.rpc.table.*; import com.alipay.oceanbase.rpc.table.api.TableBatchOps; import com.alipay.oceanbase.rpc.table.api.TableQuery; -import com.alipay.oceanbase.rpc.threadlocal.ThreadLocalMap; import com.alipay.oceanbase.rpc.util.*; import com.alipay.remoting.util.StringUtils; import org.slf4j.Logger; @@ -53,8 +52,6 @@ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import static com.alipay.oceanbase.rpc.constant.Constants.*; -import static com.alipay.oceanbase.rpc.location.model.ObServerRoute.STRONG_READ; import static com.alipay.oceanbase.rpc.property.Property.*; import static com.alipay.oceanbase.rpc.protocol.payload.Constants.INVALID_TABLET_ID; import static com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableOperationType.*; @@ -86,7 +83,7 @@ public class ObTableClient extends AbstractObTableClient implements Lifecycle { Constants.PROXY_SYS_USER_NAME, ""); - private volatile TableRoute tableRoute = null; + private volatile TableRoute tableRoute = new TableRoute(this, sysUA); private volatile RunningMode runningMode = RunningMode.NORMAL; @@ -104,17 +101,10 @@ public class ObTableClient extends AbstractObTableClient implements Lifecycle { private volatile boolean closed = false; private ReentrantLock statusLock = new ReentrantLock(); - private String currentIDC; - private ObReadConsistency readConsistency = ObReadConsistency.STRONG; - private ObRoutePolicy obRoutePolicy = ObRoutePolicy.IDC_ORDER; - private boolean odpMode = false; - private String odpAddr = "127.0.0.1"; - private int odpPort = 2883; - private Long clientId; private Map TableConfigs = new HashMap<>(); /* @@ -135,8 +125,8 @@ public void init() throws Exception { initTableConfigs(); // 3. init properties initProperties(); - // 4. init metadata - initMetadata(); + // 4. init tableRoute + tableRoute.init(); initialized = true; } catch (Throwable t) { BOOT.warn("failed to init ObTableClient", t); @@ -166,13 +156,7 @@ public void close() throws Exception { return; } closed = true; - if (tableRoute != null) { - tableRoute.close(); - ObTable odpTable = tableRoute.getOdpTable(); - if (odpTable != null) { - odpTable.close(); - } - } + tableRoute.close(); } finally { BOOT.info("ObTableClient is closed"); statusLock.unlock(); @@ -342,33 +326,6 @@ private void initProperties() { } } - private void initMetadata() throws Exception { - BOOT.info("begin initMetadata for all tables in database: {}", this.database); - this.tableRoute = new TableRoute(this, sysUA); - - if (odpMode) { - try { - tableRoute.buildOdpInfo(odpAddr, odpPort, runningMode); - } catch (Exception e) { - logger - .warn( - "The addr{}:{} failed to put into table roster, the node status may be wrong, Ignore", - odpAddr, odpPort); - throw e; - } - return; - } - // build ConfigServerInfo to get rsList - tableRoute.loadConfigServerInfo(); - - // build tableRoster and ServerRoster - TableEntryKey rootServerKey = new TableEntryKey(clusterName, tenantName, - OCEANBASE_DATABASE, ALL_DUMMY_TABLE); - tableRoute.initRoster(rootServerKey, initialized, runningMode); - // create background refresh-checker task - tableRoute.launchRouteRefresher(); - } - public boolean isOdpMode() { return odpMode; } @@ -445,13 +402,13 @@ public Object[] getRowKey() { private T execute(String tableName, TableExecuteCallback callback) throws Exception { // force strong read by default, for backward compatibility. - return execute(tableName, callback, getRoute(false)); + return execute(tableName, callback, tableRoute.getReadConsistency()); } /** * Execute with a route strategy. */ - private T execute(String tableName, TableExecuteCallback callback, ObServerRoute route) + private T execute(String tableName, TableExecuteCallback callback, ObTableConsistencyLevel currentConsistencyLevel) throws Exception { if (tableName == null || tableName.isEmpty()) { throw new IllegalArgumentException("table name is null"); @@ -487,7 +444,7 @@ private T execute(String tableName, TableExecuteCallback callback, ObServ long tabletId = tableRoute.getTabletIdByPartId(entry, partId); tableRoute.refreshPartitionLocation(tableName, tabletId, entry); } - tableParam = getTableParamWithRoute(tableName, rowKey, route); + tableParam = tableRoute.getTableParam(tableName, rowKey); } logger.debug("tableName: {}, tableParam obTable ip:port is {}:{}, ls_id: {}, tablet_id: {}", tableName, tableParam.getObTable().getIp(), tableParam.getObTable().getPort(), tableParam.getLsId(), tableParam.getTabletId()); @@ -519,7 +476,6 @@ private T execute(String tableName, TableExecuteCallback callback, ObServ if (ex instanceof ObTableReplicaNotReadableException) { if (tableParam != null && System.currentTimeMillis() - startExecute < runtimeMaxWait) { logger.warn("retry when replica not readable: {}", ex.getMessage()); - route.addToBlackList(tableParam.getObTable().getIp()); } else { logger.warn("timeout, cause replica is not readable, tryTimes={}", tryTimes); RUNTIME.error("replica not readable", ex); @@ -654,14 +610,14 @@ public TableQuery getQuery() { private T execute(String tableName, OperationExecuteCallback callback) throws Exception { // force strong read by default, for backward compatibility. - return execute(tableName, callback, getRoute(false)); + return execute(tableName, callback, null); } /** * Execute with a route strategy for mutation */ private T execute(String tableName, OperationExecuteCallback callback, - ObServerRoute route) throws Exception { + ObTableConsistencyLevel currentConsistencyLevel) throws Exception { if (tableName == null || tableName.isEmpty()) { throw new IllegalArgumentException("table name is null"); } @@ -700,7 +656,7 @@ private T execute(String tableName, OperationExecuteCallback callback, tableRoute.refreshPartitionLocation(tableName, tabletId, entry); } // using row key - tableParam = tableRoute.getTableParamWithRoute(tableName, callback.getRowKey(), route); + tableParam = tableRoute.getTableParam(tableName, callback.getRowKey(), currentConsistencyLevel); } else if (null != callback.getQuery()) { if (tryTimes > 1 && needRefreshPartitionLocation) { needRefreshPartitionLocation = false; @@ -717,7 +673,7 @@ private T execute(String tableName, OperationExecuteCallback callback, ObTableQuery tableQuery = callback.getQuery().getObTableQuery(); // using scan range tableParam = tableRoute.getTableParam(tableName, tableQuery.getScanRangeColumns(), - tableQuery.getKeyRanges()); + tableQuery.getKeyRanges(), currentConsistencyLevel); } routeQueryTabletId = tableParam.getPartitionId(); } else { @@ -755,7 +711,6 @@ private T execute(String tableName, OperationExecuteCallback callback, if (ex instanceof ObTableReplicaNotReadableException) { if (tableParam != null && System.currentTimeMillis() - startExecute > runtimeMaxWait) { logger.warn("retry when replica not readable: {}", ex.getMessage()); - route.addToBlackList(tableParam.getObTable().getIp()); } else { logger.warn("timeout, cause replica is not readable, tryTimes={}", tryTimes); RUNTIME.error("replica not readable", ex); @@ -1008,103 +963,6 @@ public TableEntry refreshTabletLocationBatch(String tableName) throws Exception return tableRoute.refreshTabletLocationBatch(tableName); } - /** - * this method is designed for the old single operations - * @param tableName table want to get - * @param rowkey row key - * @return table param - * @throws Exception exception - */ - public ObTableParam getTableParam(String tableName, Object[] rowkey) - throws Exception { - ObServerRoute route = getRoute(false); - Row row = transformToRow(tableName, rowkey); - return tableRoute.getTableParamWithRoute(tableName, row, route); - } - - /** - * this method is designed for the old single operations - * @param tableName table want to get - * @param rowkey row key - * @return table param - * @throws Exception exception - */ - public ObTableParam getTableParamWithRoute(String tableName, Object[] rowkey, ObServerRoute route) - throws Exception { - Row row = transformToRow(tableName, rowkey); - return tableRoute.getTableParamWithRoute(tableName, row, route); - } - - /** - * this method is designed for the old single operations - * route is provided from old single operation execution and non-LS BatchOpsImpl - * @param tableName table want to get - * @param rowkey row key - * @param route server route choice - * @return table param - * @throws Exception exception - */ - public ObTableParam getTableParamWithRoute(String tableName, Row rowkey, ObServerRoute route) - throws Exception { - return tableRoute.getTableParamWithRoute(tableName, rowkey, route); - } - - /** - * this method is designed for batch operations - * get all tableParams by rowKeys - * @param tableName table want to get - * @param rowkeys list of row key - * @return table param - * @throws Exception exception - */ - public List getTableParams(String tableName, List rowkeys) throws Exception { - return tableRoute.getTableParams(tableName, rowkeys); - } - - /** - * get partition ids and addrs by start-end range - * @param tableName table want to get - * @param query query - * @param start start key - * @param startInclusive whether include start key - * @param end end key - * @param endInclusive whether include end key - * @return list of table obTableParams - * @throws Exception exception - */ - public List getTableParams(String tableName, ObTableQuery query, - Object[] start, boolean startInclusive, - Object[] end, boolean endInclusive) - throws Exception { - return tableRoute.getTableParams(tableName, query, start, startInclusive, end, endInclusive); - } - - /** - * get addr by pardId - * @param tableName table want to get - * @param partId logic of table - * @param route ObServer route - * @return ObPair of partId and table - * @throws Exception exception - */ - public ObTableParam getTableParamWithPartId(String tableName, long partId, ObServerRoute route) - throws Exception { - return tableRoute.getTableWithPartId(tableName, partId, route); - } - - /** - * get addr by pardId in ODP mode - * only support by ODP version after 4.3.2 - * @param tableName table want to get - * @param partId logic of table - * @return ObPair of partId and table - * @throws Exception exception - */ - public ObTableParam getOdpTableParamWithPartId(String tableName, long partId) - throws Exception { - return tableRoute.getOdpTableWithPartId(tableName, partId); - } - /** * * @param moveResponse reRoute response @@ -1187,6 +1045,7 @@ public void dealWithRpcTimeoutForSingleTablet(ObServerAddr addr, String tableNam RouteTableRefresher.addIntoSuspectIPs(suspectAddr); tableRoute.refreshPartitionLocation(tableName, tabletId, null); } + public void dealWithRpcTimeoutForBatchTablet(ObServerAddr addr, String tableName) throws Exception { RouteTableRefresher.SuspectObServer suspectAddr = new RouteTableRefresher.SuspectObServer(addr); RouteTableRefresher.addIntoSuspectIPs(suspectAddr); @@ -1246,7 +1105,7 @@ public Map get(final String tableName, final Object[] rowKey, throw new IllegalArgumentException("table name is null"); } final long startTime = System.currentTimeMillis(); - final ObReadConsistency obReadConsistency = this.getReadConsistency(); + final ObTableConsistencyLevel readConsistency = tableRoute.getReadConsistency(); return execute(tableName, new TableExecuteCallback>(rowKey) { @Override public Map execute(ObTableParam tableParam) throws Exception { @@ -1257,7 +1116,7 @@ public Map execute(ObTableParam tableParam) throws Exception { request.setTableId(tableParam.getTableId()); // partId/tabletId request.setPartitionId(tableParam.getPartitionId()); - request.setConsistencyLevel(obReadConsistency.toObTableConsistencyLevel()); + request.setConsistencyLevel(readConsistency); ObPayload result = executeWithRetry(obTable, request, tableName); checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); @@ -1267,7 +1126,7 @@ public Map execute(ObTableParam tableParam) throws Exception { System.currentTimeMillis() - getTableTime, getslowQueryMonitorThreshold()); return ((ObTableOperationResult) result).getEntity().getSimpleProperties(); } - }, getReadRoute()); + }, tableRoute.getReadConsistency()); } /** @@ -1308,7 +1167,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1347,7 +1206,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1388,7 +1247,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1424,7 +1283,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1465,7 +1324,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1504,7 +1363,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1524,6 +1383,20 @@ public Get get(String tableName) { */ public Map get(final String tableName, final Row rowKey, final String[] selectColumns) throws Exception { + return get(tableName, rowKey, selectColumns, null); + } + + /** + * get + * @param tableName which table to insert + * @param rowKey insert row key + * @param selectColumns select columns + * @param readConsistency read consistency + * @return execute result + * @throws Exception exception + */ + public Map get(final String tableName, final Row rowKey, + final String[] selectColumns, final ObTableConsistencyLevel readConsistency) throws Exception { final long start = System.currentTimeMillis(); return execute(tableName, new OperationExecuteCallback>(rowKey, null) { @@ -1537,6 +1410,11 @@ public Map execute(ObTableParam tableParam) throws Exception { ObTableOperationRequest request = ObTableOperationRequest.getInstance( tableName, GET, rowKey.getValues(), selectColumns, null, obTable.getObTableOperationTimeout()); + ObTableConsistencyLevel consistencyLevel = readConsistency; + if (readConsistency == null) { // when readConsistency is not set, use the global read consistency level + consistencyLevel = tableRoute.getReadConsistency(); + } + request.setConsistencyLevel(consistencyLevel); request.setTableId(tableParam.getTableId()); // partId/tabletId request.setPartitionId(tableParam.getPartitionId()); @@ -1548,7 +1426,7 @@ public Map execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getEntity().getSimpleProperties(); } - }); + }, readConsistency); } /** @@ -1587,7 +1465,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1628,7 +1506,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1667,7 +1545,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1708,7 +1586,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1751,7 +1629,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1810,7 +1688,7 @@ public Map execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getEntity().getSimpleProperties(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1855,7 +1733,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1892,7 +1770,7 @@ public Map execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getEntity().getSimpleProperties(); } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -1931,7 +1809,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }); + }, ObTableConsistencyLevel.STRONG); } /** @@ -2010,7 +1888,7 @@ private List getAllPartitionInternal(String tableName, boolean refres tableRoute.refreshMeta(tableName); } allTables = tableRoute.getTableParams(tableName, new ObTableQuery(), new Object[]{ ObObj.getMin() }, true, - new Object[]{ ObObj.getMax() }, true); + new Object[]{ ObObj.getMax() }, true, tableRoute.getReadConsistency()); } for (ObTableParam tableParam : allTables) { Partition partition = new Partition(tableParam.getPartitionId(), tableParam.getPartId(), tableParam.getTableId(), @@ -2271,6 +2149,9 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E ObTableClientQueryImpl tableQuery = new ObTableClientQueryImpl(tableName, ((ObTableQueryRequest) request).getTableQuery(), this); tableQuery.setEntityType(request.getEntityType()); + if (request.getConsistencyLevel() == ObTableConsistencyLevel.EVENTUAL) { + tableQuery.setReadConsistency("weak"); + } tableQuery.setHbaseOpType(request.getHbaseOpType()); return new ObClusterTableQuery(tableQuery).executeInternal(); } else if (request instanceof ObTableQueryAsyncRequest) { @@ -2279,6 +2160,9 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E ObTableClientQueryImpl tableQuery = new ObTableClientQueryImpl(tableName, ((ObTableQueryAsyncRequest) request).getObTableQueryRequest().getTableQuery(), this); tableQuery.setEntityType(request.getEntityType()); + if (request.getConsistencyLevel() == ObTableConsistencyLevel.EVENTUAL) { + tableQuery.setReadConsistency("weak"); + } tableQuery.setHbaseOpType(request.getHbaseOpType()); ObClusterTableQuery clusterTableQuery = new ObClusterTableQuery(tableQuery); clusterTableQuery.setAllowDistributeScan(((ObTableQueryAsyncRequest) request).isAllowDistributeScan()); @@ -2667,12 +2551,12 @@ public void setParamURL(String paramURL) throws IllegalArgumentException { BOOT.info(String.format("will set database=%s", kv[1])); } } else if (Constants.READ_CONSISTENCY.equalsIgnoreCase(kv[0])) { - readConsistency = ObReadConsistency.getByName(kv[1]); + tableRoute.setReadConsistency(kv[1]); if (BOOT.isInfoEnabled()) { BOOT.info(String.format("will set %s=%s", Constants.READ_CONSISTENCY, kv[1])); } } else if (Constants.OB_ROUTE_POLICY.equalsIgnoreCase(kv[0])) { - obRoutePolicy = ObRoutePolicy.getByName(kv[1]); + tableRoute.setRoutePolicy(ObRoutePolicy.getByName(kv[1])); if (BOOT.isInfoEnabled()) { BOOT.info(String.format("will set %s=%s", Constants.OB_ROUTE_POLICY, kv[1])); } @@ -2870,53 +2754,16 @@ public ObTableClientType getClientType(RunningMode runningMode) { } } - /** - * Get read consistency. - * @return read consistency level. - */ - public ObReadConsistency getReadConsistency() { - ObReadConsistency readConsistency = ThreadLocalMap.getReadConsistency(); - if (readConsistency == null) { - readConsistency = this.readConsistency; - } - return readConsistency; + public void setReadConsistency(String readConsistency) throws IllegalArgumentException { + tableRoute.setReadConsistency(readConsistency); } - /** - * Get OB router policy. - * @return policy - */ - public ObRoutePolicy getObRoutePolicy() { - return obRoutePolicy; - } - - /** - * Get OB router. - * @return router - */ - public ObServerRoute getReadRoute() { - if (odpMode) { - return null; - } - if (getReadConsistency().isStrong()) { - return STRONG_READ; - } - ServerRoster serverRoster = tableRoute.getServerRoster(); - return new ObServerRoute(ObReadConsistency.WEAK, obRoutePolicy, serverRoster - .getServerLdcLocation().isLdcUsed()); + public String getReadConsistency() { + return tableRoute.getReadConsistency().name(); } - /** - * Get route for read or write. - * @param readonly is readonly - * @return route - */ - public ObServerRoute getRoute(boolean readonly) { - if (readonly) { - return getReadRoute(); - } else { - return STRONG_READ; - } + public void setRoutePolicy(String policy) throws IllegalArgumentException { + tableRoute.setRoutePolicy(ObRoutePolicy.getByName(policy)); } public ObTableServerCapacity getServerCapacity() { @@ -2929,22 +2776,40 @@ public TableRoute getTableRoute() { public void setOdpAddr(String odpAddr) { this.odpAddr = odpAddr; + if (tableRoute != null && tableRoute.getOdpInfo() != null) { + tableRoute.getOdpInfo().setAddr(odpAddr); + } } public void setOdpPort(int odpPort) { this.odpPort = odpPort; + if (tableRoute != null && tableRoute.getOdpInfo() != null) { + tableRoute.getOdpInfo().setPort(odpPort); + } + } + + public String getOdpAddr() { + return odpAddr; + } + + public int getOdpPort() { + return odpPort; } /** - * Set current IDC, for testing only. + * Set current IDC for weak read routing. * @param idc idc */ public void setCurrentIDC(String idc) { - this.currentIDC = idc; + tableRoute.setCurrentIDC(idc); } + /** + * Get current IDC. + * @return current IDC + */ public String getCurrentIDC() { - return this.currentIDC; + return tableRoute.getCurrentIDC(); } /** diff --git a/src/main/java/com/alipay/oceanbase/rpc/bolt/protocol/ObTablePacketCode.java b/src/main/java/com/alipay/oceanbase/rpc/bolt/protocol/ObTablePacketCode.java index 316b700d..18abb9eb 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/bolt/protocol/ObTablePacketCode.java +++ b/src/main/java/com/alipay/oceanbase/rpc/bolt/protocol/ObTablePacketCode.java @@ -17,8 +17,6 @@ package com.alipay.oceanbase.rpc.bolt.protocol; -import com.alipay.oceanbase.rpc.exception.ObTableRoutingWrongException; -import com.alipay.oceanbase.rpc.meta.ObTableMetaRequest; import com.alipay.oceanbase.rpc.meta.ObTableMetaResponse; import com.alipay.oceanbase.rpc.protocol.packet.ObRpcPacketHeader; import com.alipay.oceanbase.rpc.protocol.payload.ObPayload; @@ -36,9 +34,6 @@ import com.alipay.oceanbase.rpc.protocol.payload.impl.login.ObTableLoginResult; import com.alipay.remoting.CommandCode; -import static com.alipay.oceanbase.rpc.protocol.payload.Pcodes.OB_TABLE_API_HBASE_EXECUTE; -import static com.alipay.oceanbase.rpc.protocol.payload.Pcodes.OB_TABLE_API_META_INFO_EXECUTE; - public enum ObTablePacketCode implements CommandCode { OB_TABLE_API_LOGIN(Pcodes.OB_TABLE_API_LOGIN) { diff --git a/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObClientFuture.java b/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObClientFuture.java index bf23b05f..7effce99 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObClientFuture.java +++ b/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObClientFuture.java @@ -22,7 +22,6 @@ import com.alipay.remoting.InvokeContext; import com.alipay.remoting.InvokeFuture; import com.alipay.remoting.RemotingCommand; -import com.alipay.oceanbase.rpc.exception.ObTableTimeoutExcetion; import io.netty.util.Timeout; import java.net.InetSocketAddress; diff --git a/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObTableConnection.java b/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObTableConnection.java index 218dea5c..eecb9f9d 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObTableConnection.java +++ b/src/main/java/com/alipay/oceanbase/rpc/bolt/transport/ObTableConnection.java @@ -119,7 +119,8 @@ private boolean connect() throws Exception { if (tries >= maxTryTimes) { if (!obTable.isOdpMode()) { - RouteTableRefresher.SuspectObServer suspectAddr = new RouteTableRefresher.SuspectObServer(obTable.getObServerAddr()); + RouteTableRefresher.SuspectObServer suspectAddr = new RouteTableRefresher.SuspectObServer( + obTable.getObServerAddr()); RouteTableRefresher.addIntoSuspectIPs(suspectAddr); } LOGGER.warn("connect failed after max " + maxTryTimes + " tries " diff --git a/src/main/java/com/alipay/oceanbase/rpc/exception/ObTableSessionNotExistException.java b/src/main/java/com/alipay/oceanbase/rpc/exception/ObTableSessionNotExistException.java index c18483ec..9dc06963 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/exception/ObTableSessionNotExistException.java +++ b/src/main/java/com/alipay/oceanbase/rpc/exception/ObTableSessionNotExistException.java @@ -1,3 +1,20 @@ +/*- + * #%L + * com.oceanbase:obkv-table-client + * %% + * Copyright (C) 2021 - 2025 OceanBase + * %% + * OBKV Table Client Framework is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * #L% + */ + package com.alipay.oceanbase.rpc.exception; public class ObTableSessionNotExistException extends ObTableException { diff --git a/src/main/java/com/alipay/oceanbase/rpc/get/Get.java b/src/main/java/com/alipay/oceanbase/rpc/get/Get.java index 78db0dcc..d3e04aab 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/get/Get.java +++ b/src/main/java/com/alipay/oceanbase/rpc/get/Get.java @@ -20,22 +20,17 @@ import com.alipay.oceanbase.rpc.ObTableClient; import com.alipay.oceanbase.rpc.mutation.ColumnValue; import com.alipay.oceanbase.rpc.mutation.Row; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; import com.alipay.oceanbase.rpc.table.api.Table; import java.util.Map; public class Get { - private Table client; - private String tableName; - protected Row rowKey; - protected String[] selectColumns; - - public Get() { - tableName = null; - client = null; - rowKey = null; - selectColumns = null; - } + private Table client = null; + private String tableName = null; + private Row rowKey = null; + private String[] selectColumns = null; + private String readConsistency = ""; public Get(Table client, String tableName) { this.client = client; @@ -67,14 +62,27 @@ public Get select(String... columns) { return this; } + public Get setReadConsistency(String readConsistency) { + this.readConsistency = readConsistency; + return this; + } + + public String getReadConsistency() { + return readConsistency; + } + public String[] getSelectColumns() { return selectColumns; } public Map execute() throws Exception { + ObTableConsistencyLevel readConsistency = null; + if (this.readConsistency != null && !this.readConsistency.isEmpty()) { + readConsistency = ObTableConsistencyLevel.getByName(this.readConsistency); + } if (client == null) { throw new IllegalArgumentException("client is null"); } - return ((ObTableClient) client).get(tableName, rowKey, selectColumns); + return ((ObTableClient) client).get(tableName, rowKey, selectColumns, readConsistency); } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/LocationUtil.java b/src/main/java/com/alipay/oceanbase/rpc/location/LocationUtil.java index 4f485e15..494ae3c7 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/LocationUtil.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/LocationUtil.java @@ -56,191 +56,191 @@ public class LocationUtil { - private static final Logger logger = TableClientLoggerFactory - .getLogger(LocationUtil.class); + private static final Logger logger = TableClientLoggerFactory + .getLogger(LocationUtil.class); - private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final ObjectMapper objectMapper = new ObjectMapper(); static { objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false) - .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); + .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false) + .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); loadJdbcDriver(); } - private static final String OB_VERSION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ OB_VERSION() AS CLUSTER_VERSION;"; + private static final String OB_VERSION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ OB_VERSION() AS CLUSTER_VERSION;"; - private static final String PROXY_INDEX_INFO_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ data_table_id, table_id, index_type FROM oceanbase.__all_virtual_table " - + "where table_name = ?"; + private static final String PROXY_INDEX_INFO_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ data_table_id, table_id, index_type FROM oceanbase.__all_virtual_table " + + "where table_name = ?"; - private static final String PROXY_TABLE_ID_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ table_id from oceanbase.__all_virtual_proxy_schema " - + "where tenant_name = ? and database_name = ? and table_name = ? limit 1"; + private static final String PROXY_TABLE_ID_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ table_id from oceanbase.__all_virtual_proxy_schema " + + "where tenant_name = ? and database_name = ? and table_name = ? limit 1"; - private static final String OB_TENANT_EXIST_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ tenant_id from __all_tenant where tenant_name = ?;"; + private static final String OB_TENANT_EXIST_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ tenant_id from __all_tenant where tenant_name = ?;"; @Deprecated @SuppressWarnings("unused") - private static final String PROXY_PLAIN_SCHEMA_SQL_FORMAT = "SELECT /*+READ_CONSISTENCY(WEAK)*/ partition_id, svr_ip, sql_port, table_id, role, part_num, replica_num, schema_version, spare1 " - + "FROM oceanbase.__all_virtual_proxy_schema " - + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND partition_id in ({0}) AND sql_port > 0 " - + "ORDER BY role ASC LIMIT ?"; + private static final String PROXY_PLAIN_SCHEMA_SQL_FORMAT = "SELECT /*+READ_CONSISTENCY(WEAK)*/ partition_id, svr_ip, sql_port, table_id, role, part_num, replica_num, schema_version, spare1 " + + "FROM oceanbase.__all_virtual_proxy_schema " + + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND partition_id in ({0}) AND sql_port > 0 " + + "ORDER BY role ASC LIMIT ?"; @Deprecated @SuppressWarnings("unused") - private static final String PROXY_TENANT_SCHEMA_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ svr_ip, sql_port, table_id, role, part_num, replica_num, spare1 " - + "FROM oceanbase.__all_virtual_proxy_schema " - + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND sql_port > 0 " - + "ORDER BY partition_id ASC, role ASC LIMIT ?"; + private static final String PROXY_TENANT_SCHEMA_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ svr_ip, sql_port, table_id, role, part_num, replica_num, spare1 " + + "FROM oceanbase.__all_virtual_proxy_schema " + + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND sql_port > 0 " + + "ORDER BY partition_id ASC, role ASC LIMIT ?"; @Deprecated @SuppressWarnings("unused") - private static final String PROXY_PLAIN_SCHEMA_SQL_FORMAT_V4 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ tablet_id, svr_ip, sql_port, table_id, role, part_num, replica_num, schema_version, spare1 " - + "FROM oceanbase.__all_virtual_proxy_schema " - + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND tablet_id in ({0}) AND sql_port > 0 " - + "ORDER BY role ASC LIMIT ?"; - - private static final String PROXY_PART_INFO_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_level, part_num, part_type, part_space, part_expr, " - + "part_range_type, sub_part_num, sub_part_type, sub_part_space, sub_part_range_type, sub_part_expr, " - + "part_key_name, part_key_type, part_key_idx, part_key_extra, part_key_collation_type " - + "FROM oceanbase.__all_virtual_proxy_partition_info " - + "WHERE tenant_name = ? and table_id = ? group by part_key_name order by part_key_name LIMIT ?;"; - - private static final String PROXY_PART_INFO_SQL_V2 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_level, part_num, part_type, part_space, part_expr, " - + "part_range_type, sub_part_num, sub_part_type, sub_part_space, sub_part_range_type, sub_part_expr, " - + "part_key_name, part_key_type, part_key_idx, part_key_extra, part_key_collation_type, spare1 as schema_version " - + "FROM oceanbase.__all_virtual_proxy_partition_info " - + "WHERE tenant_name = ? and table_id = ? group by part_key_name order by part_key_name LIMIT ?;"; + private static final String PROXY_PLAIN_SCHEMA_SQL_FORMAT_V4 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ tablet_id, svr_ip, sql_port, table_id, role, part_num, replica_num, schema_version, spare1 " + + "FROM oceanbase.__all_virtual_proxy_schema " + + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND tablet_id in ({0}) AND sql_port > 0 " + + "ORDER BY role ASC LIMIT ?"; + + private static final String PROXY_PART_INFO_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_level, part_num, part_type, part_space, part_expr, " + + "part_range_type, sub_part_num, sub_part_type, sub_part_space, sub_part_range_type, sub_part_expr, " + + "part_key_name, part_key_type, part_key_idx, part_key_extra, part_key_collation_type " + + "FROM oceanbase.__all_virtual_proxy_partition_info " + + "WHERE tenant_name = ? and table_id = ? group by part_key_name order by part_key_name LIMIT ?;"; + + private static final String PROXY_PART_INFO_SQL_V2 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_level, part_num, part_type, part_space, part_expr, " + + "part_range_type, sub_part_num, sub_part_type, sub_part_space, sub_part_range_type, sub_part_expr, " + + "part_key_name, part_key_type, part_key_idx, part_key_extra, part_key_collation_type, spare1 as schema_version " + + "FROM oceanbase.__all_virtual_proxy_partition_info " + + "WHERE tenant_name = ? and table_id = ? group by part_key_name order by part_key_name LIMIT ?;"; @Deprecated @SuppressWarnings("unused") - private static final String PROXY_TENANT_SCHEMA_SQL_V4 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ svr_ip, sql_port, table_id, role, part_num, replica_num, spare1 " - + "FROM oceanbase.__all_virtual_proxy_schema " - + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND sql_port > 0 " - + "ORDER BY tablet_id ASC, role ASC LIMIT ?"; - - private static final String PROXY_DUMMY_LOCATION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ A.tablet_id as tablet_id, A.svr_ip as svr_ip, A.sql_port as sql_port, " - + "A.table_id as table_id, A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, B.stop_time as stop_time " - + ", A.spare1 as replica_type, A.schema_version as schema_version " - + "FROM oceanbase.__all_virtual_proxy_schema A inner join oceanbase.__all_server B on A.svr_ip = B.svr_ip and A.sql_port = B.inner_port " - + "WHERE tenant_name = ? and database_name=? and table_name = ?"; - - private static final String PROXY_LOCATION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ A.tablet_id as tablet_id, A.svr_ip as svr_ip, A.sql_port as sql_port, " - + "A.table_id as table_id, A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, B.stop_time as stop_time " - + ", A.spare1 as replica_type, A.schema_version as schema_version " - + "FROM oceanbase.__all_virtual_proxy_schema A inner join oceanbase.__all_server B on A.svr_ip = B.svr_ip and A.sql_port = B.inner_port " - + "WHERE tenant_name = ? and database_name=? and table_name = ? and tablet_id = 0"; - - private static final String PROXY_LOCATION_SQL_PARTITION = "SELECT /*+READ_CONSISTENCY(WEAK)*/ A.tablet_id as tablet_id, A.svr_ip as svr_ip, A.sql_port as sql_port, A.table_id as table_id, " - + " A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, " - + " B.stop_time as stop_time, A.spare1 as replica_type, A.schema_version as schema_version " - + " FROM oceanbase.__all_virtual_proxy_schema A " - + " INNER JOIN oceanbase.__all_server B ON A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port " - + " WHERE A.tablet_id IN ({0}) AND A.tenant_name = ? AND A.database_name = ? AND A.table_name = ?;"; - - private static final String PROXY_LOCATION_SQL_PARTITION_WITH_LS_ID = "SELECT /*+READ_CONSISTENCY(WEAK)*/ * FROM ( " - + " SELECT A.tablet_id as tablet__id, A.svr_ip as svr_ip, A.sql_port as sql_port, A.table_id as table_id, " - + " A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, " - + " B.stop_time as stop_time, A.spare1 as replica_type, A.schema_version as schema_version " - + " FROM oceanbase.__all_virtual_proxy_schema A " - + " INNER JOIN oceanbase.__all_server B ON A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port " - + " WHERE A.tablet_id IN ({0}) AND A.tenant_name = ? AND A.database_name = ? AND A.table_name = ?) AS left_table " - + "LEFT JOIN (" - + " SELECT D.ls_id, D.tablet_id " - + " FROM oceanbase.__all_virtual_tablet_to_ls D " - + " INNER JOIN oceanbase.DBA_OB_TENANTS C ON D.tenant_id = C.tenant_id " - + " WHERE C.tenant_name = ? " - + ") AS right_table ON left_table.tablet__id = right_table.tablet_id;"; - - private static final String TABLET_TO_LS_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ " - + "A.ls_id as ls_id, A.tablet_id as tablet_id " - + "FROM oceanbase.__all_virtual_tablet_to_ls A " - + "WHERE A.tablet_id IN ({0}) and A.tenant_id = ?"; - - private static final String PROXY_LOCATION_SQL_PARTITION_BY_TABLETID = "SELECT /*+READ_CONSISTENCY(WEAK)*/ " - + " A.tablet_id as tablet_id, " - + " A.svr_ip as svr_ip, " - + " A.sql_port as sql_port, " - + " A.table_id as table_id, " - + " A.role as role, " - + " A.replica_num as replica_num, " - + " A.part_num as part_num, " - + " A.schema_version as schema_version, " - + " (SELECT B.svr_port FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as svr_port, " - + " (SELECT B.status FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as status, " - + " (SELECT B.stop_time FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as stop_time, " - + " A.spare1 as replica_type, " - + " (SELECT D.ls_id FROM oceanbase.__all_virtual_tablet_to_ls D WHERE A.tablet_id = D.tablet_id AND D.tenant_id = " - + " (SELECT C.tenant_id FROM oceanbase.DBA_OB_TENANTS C WHERE C.tenant_name = ?)) as ls_id " - + "FROM " - + " oceanbase.__all_virtual_proxy_schema A " - + "WHERE " - + " A.tablet_id = ? " - + " AND A.tenant_name = ? " - + " AND A.database_name = ? " - + " AND A.table_name = ?;"; - - private static final String PROXY_LOCATION_SQL_PARTITION_BY_TABLETID_WITHOUT_V4 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ " - + " A.tablet_id as tablet_id, " - + " A.svr_ip as svr_ip, " - + " A.sql_port as sql_port, " - + " A.table_id as table_id, " - + " A.role as role, " - + " A.replica_num as replica_num, " - + " A.part_num as part_num, " - + " A.schema_version as schema_version, " - + " (SELECT B.svr_port FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as svr_port, " - + " (SELECT B.status FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as status, " - + " (SELECT B.stop_time FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as stop_time, " - + " A.spare1 as replica_type " - + "FROM " - + " oceanbase.__all_virtual_proxy_schema A " - + "WHERE " - + " A.tablet_id = ? " - + " AND A.tenant_name = ? " - + " AND A.database_name = ? " - + " AND A.table_name = ?;"; - - private static final String PROXY_FIRST_PARTITION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_id, part_name, tablet_id, high_bound_val, sub_part_num " - + "FROM oceanbase.__all_virtual_proxy_partition " - + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; - - private static final String PROXY_FIRST_PARTITION_SQL_V2 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_id, part_name, tablet_id, high_bound_val, sub_part_num, spare1 as schema_version " - + "FROM oceanbase.__all_virtual_proxy_partition " - + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; - - private static final String PROXY_SUB_PARTITION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ sub_part_id, part_name, tablet_id, high_bound_val " - + "FROM oceanbase.__all_virtual_proxy_sub_partition " - + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; - - private static final String PROXY_SUB_PARTITION_SQL_V2 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ sub_part_id, part_name, tablet_id, high_bound_val, spare1 as schema_version " - + "FROM oceanbase.__all_virtual_proxy_sub_partition " - + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; - - private static final String PROXY_SERVER_STATUS_INFO = "SELECT ss.svr_ip, ss.zone, zs.region, zs.idc as idc " - + "FROM DBA_OB_SERVERS ss, DBA_OB_ZONES zs " - + "WHERE zs.zone = ss.zone ;"; - - private static final String home = System - .getProperty( - "user.home", - "/home/admin"); - - private static final String TABLE_GROUP_GET_TABLE_NAME = "SELECT /*+READ_CONSISTENCY(WEAK)*/ table_name " - + "FROM oceanbase.CDB_OB_TABLEGROUP_TABLES " - + "WHERE tablegroup_name = ? and tenant_id = ? order by table_name limit 1;"; - - private static final int TEMPLATE_PART_ID = -1; + private static final String PROXY_TENANT_SCHEMA_SQL_V4 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ svr_ip, sql_port, table_id, role, part_num, replica_num, spare1 " + + "FROM oceanbase.__all_virtual_proxy_schema " + + "WHERE tenant_name = ? AND database_name = ? AND table_name = ? AND sql_port > 0 " + + "ORDER BY tablet_id ASC, role ASC LIMIT ?"; + + private static final String PROXY_DUMMY_LOCATION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ A.tablet_id as tablet_id, A.svr_ip as svr_ip, A.sql_port as sql_port, " + + "A.table_id as table_id, A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, B.stop_time as stop_time " + + ", A.spare1 as replica_type, A.schema_version as schema_version " + + "FROM oceanbase.__all_virtual_proxy_schema A inner join oceanbase.__all_server B on A.svr_ip = B.svr_ip and A.sql_port = B.inner_port " + + "WHERE tenant_name = ? and database_name=? and table_name = ?"; + + private static final String PROXY_LOCATION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ A.tablet_id as tablet_id, A.svr_ip as svr_ip, A.sql_port as sql_port, " + + "A.table_id as table_id, A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, B.stop_time as stop_time " + + ", A.spare1 as replica_type, A.schema_version as schema_version " + + "FROM oceanbase.__all_virtual_proxy_schema A inner join oceanbase.__all_server B on A.svr_ip = B.svr_ip and A.sql_port = B.inner_port " + + "WHERE tenant_name = ? and database_name=? and table_name = ? and tablet_id = 0"; + + private static final String PROXY_LOCATION_SQL_PARTITION = "SELECT /*+READ_CONSISTENCY(WEAK)*/ A.tablet_id as tablet_id, A.svr_ip as svr_ip, A.sql_port as sql_port, A.table_id as table_id, " + + " A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, " + + " B.stop_time as stop_time, A.spare1 as replica_type, A.schema_version as schema_version " + + " FROM oceanbase.__all_virtual_proxy_schema A " + + " INNER JOIN oceanbase.__all_server B ON A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port " + + " WHERE A.tablet_id IN ({0}) AND A.tenant_name = ? AND A.database_name = ? AND A.table_name = ?;"; + + private static final String PROXY_LOCATION_SQL_PARTITION_WITH_LS_ID = "SELECT /*+READ_CONSISTENCY(WEAK)*/ * FROM ( " + + " SELECT A.tablet_id as tablet__id, A.svr_ip as svr_ip, A.sql_port as sql_port, A.table_id as table_id, " + + " A.role as role, A.replica_num as replica_num, A.part_num as part_num, B.svr_port as svr_port, B.status as status, " + + " B.stop_time as stop_time, A.spare1 as replica_type, A.schema_version as schema_version " + + " FROM oceanbase.__all_virtual_proxy_schema A " + + " INNER JOIN oceanbase.__all_server B ON A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port " + + " WHERE A.tablet_id IN ({0}) AND A.tenant_name = ? AND A.database_name = ? AND A.table_name = ?) AS left_table " + + "LEFT JOIN (" + + " SELECT D.ls_id, D.tablet_id " + + " FROM oceanbase.__all_virtual_tablet_to_ls D " + + " INNER JOIN oceanbase.DBA_OB_TENANTS C ON D.tenant_id = C.tenant_id " + + " WHERE C.tenant_name = ? " + + ") AS right_table ON left_table.tablet__id = right_table.tablet_id;"; + + private static final String TABLET_TO_LS_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ " + + "A.ls_id as ls_id, A.tablet_id as tablet_id " + + "FROM oceanbase.__all_virtual_tablet_to_ls A " + + "WHERE A.tablet_id IN ({0}) and A.tenant_id = ?"; + + private static final String PROXY_LOCATION_SQL_PARTITION_BY_TABLETID = "SELECT /*+READ_CONSISTENCY(WEAK)*/ " + + " A.tablet_id as tablet_id, " + + " A.svr_ip as svr_ip, " + + " A.sql_port as sql_port, " + + " A.table_id as table_id, " + + " A.role as role, " + + " A.replica_num as replica_num, " + + " A.part_num as part_num, " + + " A.schema_version as schema_version, " + + " (SELECT B.svr_port FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as svr_port, " + + " (SELECT B.status FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as status, " + + " (SELECT B.stop_time FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as stop_time, " + + " A.spare1 as replica_type, " + + " (SELECT D.ls_id FROM oceanbase.__all_virtual_tablet_to_ls D WHERE A.tablet_id = D.tablet_id AND D.tenant_id = " + + " (SELECT C.tenant_id FROM oceanbase.DBA_OB_TENANTS C WHERE C.tenant_name = ?)) as ls_id " + + "FROM " + + " oceanbase.__all_virtual_proxy_schema A " + + "WHERE " + + " A.tablet_id = ? " + + " AND A.tenant_name = ? " + + " AND A.database_name = ? " + + " AND A.table_name = ?;"; + + private static final String PROXY_LOCATION_SQL_PARTITION_BY_TABLETID_WITHOUT_V4 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ " + + " A.tablet_id as tablet_id, " + + " A.svr_ip as svr_ip, " + + " A.sql_port as sql_port, " + + " A.table_id as table_id, " + + " A.role as role, " + + " A.replica_num as replica_num, " + + " A.part_num as part_num, " + + " A.schema_version as schema_version, " + + " (SELECT B.svr_port FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as svr_port, " + + " (SELECT B.status FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as status, " + + " (SELECT B.stop_time FROM oceanbase.__all_server B WHERE A.svr_ip = B.svr_ip AND A.sql_port = B.inner_port) as stop_time, " + + " A.spare1 as replica_type " + + "FROM " + + " oceanbase.__all_virtual_proxy_schema A " + + "WHERE " + + " A.tablet_id = ? " + + " AND A.tenant_name = ? " + + " AND A.database_name = ? " + + " AND A.table_name = ?;"; + + private static final String PROXY_FIRST_PARTITION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_id, part_name, tablet_id, high_bound_val, sub_part_num " + + "FROM oceanbase.__all_virtual_proxy_partition " + + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; + + private static final String PROXY_FIRST_PARTITION_SQL_V2 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ part_id, part_name, tablet_id, high_bound_val, sub_part_num, spare1 as schema_version " + + "FROM oceanbase.__all_virtual_proxy_partition " + + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; + + private static final String PROXY_SUB_PARTITION_SQL = "SELECT /*+READ_CONSISTENCY(WEAK)*/ sub_part_id, part_name, tablet_id, high_bound_val " + + "FROM oceanbase.__all_virtual_proxy_sub_partition " + + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; + + private static final String PROXY_SUB_PARTITION_SQL_V2 = "SELECT /*+READ_CONSISTENCY(WEAK)*/ sub_part_id, part_name, tablet_id, high_bound_val, spare1 as schema_version " + + "FROM oceanbase.__all_virtual_proxy_sub_partition " + + "WHERE tenant_name = ? and table_id = ? LIMIT ?;"; + + private static final String PROXY_SERVER_STATUS_INFO = "SELECT ss.svr_ip, ss.svr_port, ss.zone, zs.region, zs.idc as idc " + + "FROM DBA_OB_SERVERS ss, DBA_OB_ZONES zs " + + "WHERE zs.zone = ss.zone ;"; + + private static final String home = System + .getProperty( + "user.home", + "/home/admin"); + + private static final String TABLE_GROUP_GET_TABLE_NAME = "SELECT /*+READ_CONSISTENCY(WEAK)*/ table_name " + + "FROM oceanbase.CDB_OB_TABLEGROUP_TABLES " + + "WHERE tablegroup_name = ? and tenant_id = ? order by table_name limit 1;"; + + private static final int TEMPLATE_PART_ID = -1; // limit the size of get tableEntry location from remote each time - private static final int MAX_TABLET_BATCH_NUMS = Integer - .parseInt(System - .getProperty( - "max.table.num.epoch", - "300")); - private static final int TABLE_ENTRY_LOCATION_REFRESH_THRESHOLD = Integer - .parseInt(System - .getProperty( - "table.entry.location.refresh.threshold", - "0")); + private static final int MAX_TABLET_BATCH_NUMS = Integer + .parseInt(System + .getProperty( + "max.table.num.epoch", + "300")); + private static final int TABLE_ENTRY_LOCATION_REFRESH_THRESHOLD = Integer + .parseInt(System + .getProperty( + "table.entry.location.refresh.threshold", + "0")); private abstract static class TableEntryRefreshWithPriorityCallback { abstract T execute(ObServerAddr obServerAddr) throws ObTableEntryRefreshException; @@ -307,7 +307,7 @@ public static List getServerLdc(ServerRoster serverRoster, * @return */ public static String formatObServerUrl(ObServerAddr obServerAddr, long connectTimeout, - long socketTimeout) { + long socketTimeout) { return format( "jdbc:mysql://%s/oceanbase?useUnicode=true&characterEncoding=utf-8&connectTimeout=%d&socketTimeout=%d", obServerAddr.getIp() + ":" + obServerAddr.getSqlPort(), connectTimeout, socketTimeout); @@ -321,7 +321,7 @@ public static String formatObServerUrl(ObServerAddr obServerAddr, long connectTi * @throws ObTableEntryRefreshException */ public static Connection getMetaRefreshConnection(String url, ObUserAuth sysUA) - throws ObTableEntryRefreshException { + throws ObTableEntryRefreshException { try { return DriverManager.getConnection(url, sysUA.getUserName(), sysUA.getPassword()); @@ -340,7 +340,7 @@ private static void loadJdbcDriver() { } catch (ClassNotFoundException e) { RUNTIME.error(LCD.convert("01-00006"), e.getMessage(), e); throw new ObTableEntryRefreshException(format("fail to find jdbc driver, errMsg=%s", - e.getMessage()), e); + e.getMessage()), e); } try { @@ -377,10 +377,11 @@ private static List callServerLdcRefresh(ObServerAddr obServerA rs = ps.executeQuery(); while (rs.next()) { String ip = rs.getString("svr_ip"); + int svrPort = rs.getInt("svr_port"); String zone = rs.getString("zone"); String idc = rs.getString("idc"); String region = rs.getString("region"); - ss.add(new ObServerLdcItem(ip, zone, idc, region)); + ss.add(new ObServerLdcItem(ip, svrPort, zone, idc, region)); } } catch (SQLException e) { RUNTIME.error(LCD.convert("01-00027"), url, e); @@ -635,8 +636,8 @@ private static String getTableNameByGroupNameFromRemote(Connection connection, T } } catch (SQLException e) { RUNTIME.error("getTableNameByGroupNameFromRemote meet SQL exception", e); - throw new ObTableEntryRefreshException(format("fail to get table name from remote, key=%s", - key), e, true); + throw new ObTableEntryRefreshException(format( + "fail to get table name from remote, key=%s", key), e, true); } catch (ObTableNotExistException e) { // avoid to refresh meta for ObTableNotExistException RUNTIME.error("getTableNameByGroupNameFromRemote meet exception", e); @@ -1497,9 +1498,12 @@ private static ObPartitionEntry getPartitionLocationFromResultSetByTablet(TableE while (rs.next()) { if (ObGlobal.isSchemaVersionSupport()) { long curSchemaVersion = rs.getLong("schema_version"); - String errMsg = "getPartitionLocationFromResultSetByTablet schema_version does not match for table: " + tableEntry.getTableEntryKey().getTableName() - + ", exist version: " + schemaVersion - + ", new version: " + curSchemaVersion; + String errMsg = "getPartitionLocationFromResultSetByTablet schema_version does not match for table: " + + tableEntry.getTableEntryKey().getTableName() + + ", exist version: " + + schemaVersion + + ", new version: " + + curSchemaVersion; checkSchemaVersionMatch(schemaVersion, curSchemaVersion, errMsg); } ReplicaLocation replica = buildReplicaLocation(rs); @@ -1574,9 +1578,12 @@ private static ObPartitionEntry getPartitionLocationFromResultSet(TableEntry tab while (rs.next()) { if (ObGlobal.isSchemaVersionSupport()) { long curSchemaVersion = rs.getLong("schema_version"); - String errMsg = "getPartitionLocationFromResultSet schema_version does not match for table: " + tableEntry.getTableEntryKey().getTableName() - + ", exist version: " + schemaVersion - + ", new version: " + curSchemaVersion; + String errMsg = "getPartitionLocationFromResultSet schema_version does not match for table: " + + tableEntry.getTableEntryKey().getTableName() + + ", exist version: " + + schemaVersion + + ", new version: " + + curSchemaVersion; checkSchemaVersionMatch(schemaVersion, curSchemaVersion, errMsg); } ReplicaLocation replica = buildReplicaLocation(rs); @@ -1646,10 +1653,7 @@ private static ReplicaLocation buildReplicaLocation(ResultSet rs) throws SQLExce ObReplicaType replicaType = ObReplicaType.getReplicaType(rs.getInt("replica_type")); ReplicaLocation replica = new ReplicaLocation(); - ObServerAddr obServerAddr = new ObServerAddr(); - obServerAddr.setAddress(ip); - obServerAddr.setSqlPort(port); - obServerAddr.setSvrPort(svrPort); + ObServerAddr obServerAddr = new ObServerAddr(ip, port, svrPort); ObServerInfo obServerInfo = new ObServerInfo(); obServerInfo.setStatus(status); @@ -1720,9 +1724,10 @@ private static ObPartitionInfo parsePartitionInfo(ResultSet rs, TableEntry table while (rs.next()) { if (ObGlobal.isSchemaVersionSupport()) { long curSchemaVersion = rs.getLong("schema_version"); - String errMsg = "parsePartitionInfo schema_version does not match for table: " + tableEntry.getTableEntryKey().getTableName() - + ", exist version: " + schemaVersion - + ", new version: " + curSchemaVersion; + String errMsg = "parsePartitionInfo schema_version does not match for table: " + + tableEntry.getTableEntryKey().getTableName() + + ", exist version: " + schemaVersion + ", new version: " + + curSchemaVersion; checkSchemaVersionMatch(schemaVersion, curSchemaVersion, errMsg); } // get part info for the first loop @@ -1988,9 +1993,9 @@ private static Map parseKeyHashPart(ResultSet rs, TableEntry tableEn while (rs.next()) { if (ObGlobal.isSchemaVersionSupport()) { long curSchemaVersion = rs.getLong("schema_version"); - String errMsg = "parseKeyHashPart schema_version does not match for table: " + tableEntry.getTableEntryKey().getTableName() - + ", is sub part: " + isSubPart - + ", exist version: " + schemaVersion + String errMsg = "parseKeyHashPart schema_version does not match for table: " + + tableEntry.getTableEntryKey().getTableName() + ", is sub part: " + + isSubPart + ", exist version: " + schemaVersion + ", new version: " + curSchemaVersion; checkSchemaVersionMatch(schemaVersion, curSchemaVersion, errMsg); } @@ -2049,9 +2054,9 @@ private static List> parseRangePart(ResultS while (rs.next()) { if (ObGlobal.isSchemaVersionSupport()) { long curSchemaVersion = rs.getLong("schema_version"); - String errMsg = "parseRangePart schema_version does not match for table: " + tableEntry.getTableEntryKey().getTableName() - + ", is sub part: " + isSubPart - + ", exist version: " + schemaVersion + String errMsg = "parseRangePart schema_version does not match for table: " + + tableEntry.getTableEntryKey().getTableName() + ", is sub part: " + + isSubPart + ", exist version: " + schemaVersion + ", new version: " + curSchemaVersion; checkSchemaVersionMatch(schemaVersion, curSchemaVersion, errMsg); } @@ -2147,9 +2152,10 @@ private static Map parseListPartSets(ResultSet rs, TableEn while (rs.next()) { if (ObGlobal.isSchemaVersionSupport()) { long curSchemaVersion = rs.getLong("schema_version"); - String errMsg = "parseListPartSets schema_version does not match for table: " + tableEntry.getTableEntryKey().getTableName() - + ", exist version: " + schemaVersion - + ", new version: " + curSchemaVersion; + String errMsg = "parseListPartSets schema_version does not match for table: " + + tableEntry.getTableEntryKey().getTableName() + + ", exist version: " + schemaVersion + ", new version: " + + curSchemaVersion; checkSchemaVersionMatch(schemaVersion, curSchemaVersion, errMsg); } String[] setArray = parseListPartSetsCommon(rs, tableEntry); @@ -2179,7 +2185,8 @@ private static Map parseListPartSets(ResultSet rs, TableEn return sets; } - private static void checkSchemaVersionMatch(long expect, long actual, String errMsg) throws ObTableSchemaVersionMismatchException { + private static void checkSchemaVersionMatch(long expect, long actual, String errMsg) + throws ObTableSchemaVersionMismatchException { if (expect != actual) { logger.warn(errMsg); throw new ObTableSchemaVersionMismatchException(errMsg); @@ -2227,32 +2234,6 @@ public static ConfigServerInfo loadRsListForConfigServerInfo(ConfigServerInfo co return newConfigServer; } - public static ConfigServerInfo refreshIDC2RegionMapFroConfigServerInfo(ConfigServerInfo configServer, - String paramURL, - int connectTimeout, - int readTimeout, - int retryTimes, - long retryInternal) - throws Exception { - String obIdcRegionURL = paramURL.replace(Constants.OCP_ROOT_SERVICE_ACTION, - Constants.OCP_IDC_REGION_ACTION); - - OcpResponse ocpResponse = getRemoteOcpIdcRegionOrNull(obIdcRegionURL, connectTimeout, - readTimeout, retryTimes, retryInternal); - - if (ocpResponse != null) { - OcpResponseData ocpResponseData = ocpResponse.getData(); - if (ocpResponseData != null && ocpResponseData.getIDCList() != null) { - HashMap idc2Region = configServer.getIdc2Region(); - idc2Region.clear(); - for (OcpResponseDataIDC idcRegion : ocpResponseData.getIDCList()) { - configServer.addIdc2Region(idcRegion.getIdc(), idcRegion.getRegion()); - } - } - } - return configServer; - } - /* * Load ocp model. */ @@ -2286,27 +2267,12 @@ public static ConfigServerInfo loadConfigServerInfo(String paramURL, String data } if (rsList.isEmpty()) { - RUNTIME.error("load rs list failed dataSource: " + dataSourceName + " paramURL:" - + paramURL + " response:" + ocpResponse); + RUNTIME.warn("load rs list failed dataSource: " + dataSourceName + " paramURL:" + + paramURL + " response:" + ocpResponse); throw new RuntimeException("load rs list failed dataSource: " + dataSourceName + " paramURL:" + paramURL + " response:" + ocpResponse); } - // Get IDC -> Region map if any. - String obIdcRegionURL = paramURL.replace(Constants.OCP_ROOT_SERVICE_ACTION, - Constants.OCP_IDC_REGION_ACTION); - - ocpResponse = getRemoteOcpIdcRegionOrNull(obIdcRegionURL, connectTimeout, readTimeout, - retryTimes, retryInternal); - - if (ocpResponse != null) { - OcpResponseData ocpResponseData = ocpResponse.getData(); - if (ocpResponseData != null && ocpResponseData.getIDCList() != null) { - for (OcpResponseDataIDC idcRegion : ocpResponseData.getIDCList()) { - configServer.addIdc2Region(idcRegion.getIdc(), idcRegion.getRegion()); - } - } - } return configServer; } @@ -2337,8 +2303,7 @@ private static OcpResponse getRemoteOcpResponseOrNull(String paramURL, String da } if (tries >= tryTimes) { - RUNTIME - .error("Fail to get OCP response after " + tryTimes + " tries from [" + paramURL); + RUNTIME.warn("Fail to get OCP response after " + tryTimes + " tries from [" + paramURL); throw new ObTableRetryExhaustedException("Fail to get OCP response after " + tryTimes + " tries from [" + paramURL + "], the content is [" + content + "]", cause); @@ -2374,15 +2339,15 @@ private static OcpResponse getRemoteOcpIdcRegionOrNull(String paramURL, int conn return ocpResponse; } } catch (Exception e) { - RUNTIME.error(LCD.convert("01-00017"), e); + RUNTIME.warn(LCD.convert("01-00017"), e); Thread.sleep(retryInternal); } } if (tries >= tryTimes) { - RUNTIME.error(LCD.convert("01-00017"), "OCP IdcRegion after" + tryTimes - + " tries from [" + paramURL - + "], the content is [" + content + "]"); + RUNTIME.warn(LCD.convert("01-00017"), "OCP IdcRegion after" + tryTimes + + " tries from [" + paramURL + + "], the content is [" + content + "]"); } return null; } @@ -2508,10 +2473,12 @@ public static void parseObVerionFromLogin(String serverVersion) Pattern pattern; if (serverVersion.startsWith("OceanBase_CE")) { // serverVersion in CE is like "OceanBase_CE 4.0.0.0 (+ Obproxy 4.3.6.0), content in () is optional and valid after Obproxy 4.3.5" - pattern = Pattern.compile("OceanBase_CE\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(\\s+\\+\\s+(Obproxy)\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))?"); + pattern = Pattern + .compile("OceanBase_CE\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(\\s+\\+\\s+(Obproxy)\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))?"); } else { // serverVersion is like "OceanBase 4.0.0.0 (+ Obproxy 4.3.6.0), content in () is optional and valid after Obproxy 4.3.5" - pattern = Pattern.compile("OceanBase\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(\\s+\\+\\s+(Obproxy)\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))?"); + pattern = Pattern + .compile("OceanBase\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)(\\s+\\+\\s+(Obproxy)\\s+(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+))?"); } Matcher matcher = pattern.matcher(serverVersion); if (matcher.find() && ObGlobal.OB_VERSION == 0) { @@ -2520,14 +2487,14 @@ public static void parseObVerionFromLogin(String serverVersion) (byte) Integer.parseInt(matcher.group(3)), (byte) Integer.parseInt(matcher.group(4))); if (matcher.group(5) != null && matcher.group(6) != null) { // Obproxy part - ObGlobal.OB_PROXY_VERSION = ObGlobal.calcVersion(Integer.parseInt(matcher.group(7)), - (short) Integer.parseInt(matcher.group(8)), - (byte) Integer.parseInt(matcher.group(9)), - (byte) Integer.parseInt(matcher.group(10))); + ObGlobal.OB_PROXY_VERSION = ObGlobal.calcVersion( + Integer.parseInt(matcher.group(7)), (short) Integer.parseInt(matcher.group(8)), + (byte) Integer.parseInt(matcher.group(9)), + (byte) Integer.parseInt(matcher.group(10))); } if (ObGlobal.obVsnMajor() < 4) { throw new FeatureNotSupportedException( - "The current client version supports only server version greater than or equal to 4.0.0.0"); + "The current client version supports only server version greater than or equal to 4.0.0.0"); } } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ConfigServerInfo.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ConfigServerInfo.java index 690513a3..54926ff5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ConfigServerInfo.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/ConfigServerInfo.java @@ -17,7 +17,6 @@ package com.alipay.oceanbase.rpc.location.model; -import java.util.HashMap; import java.util.List; public class ConfigServerInfo { @@ -25,7 +24,6 @@ public class ConfigServerInfo { private String localFile; // read from local file private List rsList; private long clusterId = -1; - private HashMap idc2Region = new HashMap(); public void setRsList(List rsList) { this.rsList = rsList; @@ -59,29 +57,11 @@ public List getRsList() { return this.rsList; } - /* - * Get Region by IDC. - */ - public String getIdc2Region(String idc) { - return idc2Region.get(idc); - } - - public HashMap getIdc2Region() { - return idc2Region; - } - - /* - * Add Idc-Region pair. - */ - public void addIdc2Region(String idc, String region) { - idc2Region.put(idc, region); - } - /* * To string. */ @Override public String toString() { - return "OcpModel{" + "obServerAddrs=" + rsList + ", idc2Region=" + idc2Region + '}'; + return "OcpModel{" + "obServerAddrs=" + rsList + '}'; } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObReadConsistency.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObReadConsistency.java deleted file mode 100644 index c7d19394..00000000 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObReadConsistency.java +++ /dev/null @@ -1,100 +0,0 @@ -/*- - * #%L - * OBKV Table Client Framework - * %% - * Copyright (C) 2021 OceanBase - * %% - * OBKV Table Client Framework is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - * #L% - */ - -package com.alipay.oceanbase.rpc.location.model; - -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; - -import java.util.HashMap; -import java.util.Map; - -public enum ObReadConsistency { - - STRONG(0), WEAK(1); - - private int value; - private static Map map = new HashMap(); - - ObReadConsistency(int value) { - this.value = value; - } - - static { - for (ObReadConsistency type : ObReadConsistency.values()) { - map.put(type.value, type); - } - } - - /* - * Value of. - */ - public static ObReadConsistency valueOf(int value) { - return map.get(value); - } - - /* - * Get value. - */ - public int getValue() { - return value; - } - - /* - * Get byte value. - */ - public byte getByteValue() { - return (byte) value; - } - - /* - * Get ObReadConsistency by string value, return "STRONG" by default. - */ - static public ObReadConsistency getByName(String consistency) { - if (consistency.equalsIgnoreCase("weak")) { - return ObReadConsistency.WEAK; - } - return ObReadConsistency.STRONG; - } - - /* - * Is Strong consistency or not. - * - * @return - */ - public boolean isStrong() { - return this.value == STRONG.value; - } - - /* - * Is weak consistency or not. - * - * @return - */ - public boolean isWeak() { - return this.value == WEAK.value; - } - - /* - * Convert to ObTableConsistencyLevel. - */ - public ObTableConsistencyLevel toObTableConsistencyLevel() { - if (isWeak()) { - return ObTableConsistencyLevel.EVENTUAL; - } - return ObTableConsistencyLevel.STRONG; - } -} diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObRoutePolicy.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObRoutePolicy.java index 43ec4fc0..02e84cce 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObRoutePolicy.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObRoutePolicy.java @@ -20,23 +20,9 @@ import java.util.HashMap; import java.util.Map; -/** - * There are PRIMARY(P), FOLLOWER(F) and READONLY(R) follower types. - * ObRoutePolicy defines the weak read routing policy. - * - */ public enum ObRoutePolicy { - // read order: same IDC -> same region -> other region - IDC_ORDER(0) - // read order: F+R -> P - , FOLLOWER_FIRST(1) - // read order: R -> F -> P - // , READONLY_FIRST(2) - // read from: R - // , ONLY_READONLY(3) - // read from: P + F - // , ONLY_READWRITE(4) - ; + FOLLOWER_FIRST(0), + FOLLOWER_ONLY(1); private int value; @@ -58,22 +44,15 @@ public enum ObRoutePolicy { } /* - * Get ObRoutePolicy name, return "IDC_ORDER" by default. + * Get ObRoutePolicy name. */ - static public ObRoutePolicy getByName(String routePolicy) { - if (routePolicy != null) { - if (routePolicy.equalsIgnoreCase("idc_order")) { - return ObRoutePolicy.IDC_ORDER; - } else if (routePolicy.equalsIgnoreCase("follower_first")) { - return ObRoutePolicy.FOLLOWER_FIRST; - } /*else if (routePolicy.equalsIgnoreCase("readonly_first")) { - return ObRoutePolicy.READONLY_FIRST; - } else if (routePolicy.equalsIgnoreCase("only_readonly")) { - return ObRoutePolicy.ONLY_READONLY; - } else if (routePolicy.equalsIgnoreCase("only_readwrite")) { - return ObRoutePolicy.ONLY_READWRITE; - }*/ + static public ObRoutePolicy getByName(String routePolicy) throws IllegalArgumentException { + if (routePolicy.equalsIgnoreCase("follower_first")) { + return ObRoutePolicy.FOLLOWER_FIRST; + } else if (routePolicy.equalsIgnoreCase("follower_only")) { + return ObRoutePolicy.FOLLOWER_ONLY; + } else { + throw new IllegalArgumentException("routePolicy is invalid: " + routePolicy); } - return ObRoutePolicy.IDC_ORDER; } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerAddr.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerAddr.java index d15ee269..b769c472 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerAddr.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerAddr.java @@ -28,6 +28,20 @@ public class ObServerAddr implements Comparable { private volatile long grantPriorityTime = 0; private volatile long lastAccessTime = System.currentTimeMillis(); + public ObServerAddr() { + } + + public ObServerAddr(String ip, int svrPort) { + this.ip = ip; + this.svrPort = svrPort; + } + + public ObServerAddr(String ip, int sqlPort, int svrPort) { + this.ip = ip; + this.sqlPort = sqlPort; + this.svrPort = svrPort; + } + /* * Whether the addr is expired given the timeout. */ diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcItem.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcItem.java index 8712b4f2..d254f7c4 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcItem.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcItem.java @@ -23,20 +23,23 @@ */ public class ObServerLdcItem { private String ip; - private String zone; // concept of OceanBase - private String idc; // physical idc + private int svrPort; + private String zone; // concept of OceanBase + private String idc; // physical idc private String region; // city /* * Constructor. * * @param ip + * @param svrPort * @param zone * @param idc * @param region */ - public ObServerLdcItem(String ip, String zone, String idc, String region) { + public ObServerLdcItem(String ip, int svrPort, String zone, String idc, String region) { this.ip = ip; + this.svrPort = svrPort; this.zone = zone; this.idc = idc; this.region = region; @@ -49,6 +52,13 @@ public String getIp() { return ip; } + /* + * Get server port. + */ + public int getSvrPort() { + return svrPort; + } + /* * Get Zone of the server. */ @@ -75,7 +85,7 @@ public String getRegion() { */ @Override public String toString() { - return "ObServerLdcItem{" + "ip='" + ip + '\'' + ", zone='" + zone + '\'' + ", idc='" + idc - + '\'' + ", region='" + region + '\'' + '}'; + return "ObServerLdcItem{" + "ip='" + ip + '\'' + ", svrPort=" + svrPort + ", zone='" + zone + + '\'' + ", idc='" + idc + '\'' + ", region='" + region + '\'' + '}'; } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcLocation.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcLocation.java index 100915dd..53057917 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcLocation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerLdcLocation.java @@ -45,19 +45,17 @@ enum RegionMatchType { private HashMap otherRegion = new HashMap(); /* - * 构造 ObServerLdcLocation,根据当前 IDC 和 RegionMap 将服务器按 IDC->Region->OtherRegion的分类整理。 + * 构造 ObServerLdcLocation,根据当前 IDC 和 Region 将服务器按 IDC->Region->OtherRegion的分类整理。 * * @param allServers * @param currentIDC - * @param regionFromOcp */ - public static ObServerLdcLocation buildLdcLocation(List allServers, - String currentIDC, String regionFromOcp) { + public static ObServerLdcLocation buildLdcLocation(List allServers, String currentIDC) { ObServerLdcLocation loc = new ObServerLdcLocation(); loc.allServers = allServers; loc.currentIDC = currentIDC; - if (StringUtil.isEmpty(currentIDC)) { + if (currentIDC == null || StringUtil.isEmpty(currentIDC)) { loc.isLdcUsed = false; } else { // get Region names, refer to odp: ObLDCLocation::get_region_name @@ -77,11 +75,6 @@ public static ObServerLdcLocation buildLdcLocation(List allServ } } } - // 3. 再次从 ocp 找 idc-> region 映射 - if (loc.regionNames.isEmpty() && StringUtil.isNotEmpty(regionFromOcp)) { - loc.regionNames.add(regionFromOcp); - loc.matchType = RegionMatchType.MATCHED_BY_URL; - } if (!loc.regionNames.isEmpty()) { loc.isLdcUsed = true; @@ -92,11 +85,11 @@ public static ObServerLdcLocation buildLdcLocation(List allServ // classify by idc->region->other for (ObServerLdcItem it : allServers) { if (it.getIdc().equalsIgnoreCase(currentIDC)) { - loc.sameIDC.put(it.getIp(), it); + loc.sameIDC.put(it.getIp() + it.getSvrPort(), it); } else if (loc.regionNames.contains(it.getRegion())) { - loc.sameRegion.put(it.getIp(), it); + loc.sameRegion.put(it.getIp() + it.getSvrPort(), it); } else { - loc.otherRegion.put(it.getIp(), it); + loc.otherRegion.put(it.getIp() + it.getSvrPort(), it); } } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerRoute.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerRoute.java deleted file mode 100644 index f3bbc453..00000000 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ObServerRoute.java +++ /dev/null @@ -1,105 +0,0 @@ -/*- - * #%L - * OBKV Table Client Framework - * %% - * Copyright (C) 2021 OceanBase - * %% - * OBKV Table Client Framework is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - * #L% - */ - -package com.alipay.oceanbase.rpc.location.model; - -import java.util.HashSet; -import java.util.Set; - -/** - * ObServerRoute defines the route policy and server LDC for table operation request. - * It also keeps the black list of servers which failed to access. - * - */ -public class ObServerRoute { - // default route for strong read. - public static ObServerRoute STRONG_READ = new ObServerRoute(ObReadConsistency.STRONG); - private ObReadConsistency readConsistency; - private ObRoutePolicy readRoutePolicy; - private boolean isLdcUsed; - // black ip list - private Set blackIpList = new HashSet(); - - /* - * Construct OB Server Route. - */ - private ObServerRoute(ObReadConsistency readConsistency) { - this(readConsistency, ObRoutePolicy.IDC_ORDER, false); - } - - /* - * Construct OB Server Route. - */ - public ObServerRoute(ObReadConsistency readConsistency, ObRoutePolicy readRoutePolicy, - boolean isLdcUsed) { - - this.readConsistency = readConsistency; - this.readRoutePolicy = readRoutePolicy; - this.isLdcUsed = isLdcUsed; - } - - /* - * Get Consistency Level. - */ - public ObReadConsistency getReadConsistency() { - return readConsistency; - } - - /* - * Get read route policy. - */ - public ObRoutePolicy getReadRoutePolicy() { - return readRoutePolicy; - } - - /* - * Check whether LDC enabled. - */ - public boolean isLdcEnabled() { - return isLdcUsed; - } - - /* - * Reset route, which will clean the black ip list. - */ - public void reset() { - blackIpList.clear(); - } - - /* - * Check whether ip is in black list. - */ - public boolean isInBlackList(String ip) { - return blackIpList.contains(ip); - } - - /* - * Add ip into black list. - */ - public void addToBlackList(String ip) { - blackIpList.add(ip); - } - - /* - * set blackIpList. - */ - public void setBlackList(Set blackIpList) { - if (blackIpList != null) { - this.blackIpList = blackIpList; - } - } -} diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/OdpInfo.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/OdpInfo.java index ec9a2fd7..43d720c1 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/OdpInfo.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/OdpInfo.java @@ -38,21 +38,32 @@ public void setAddr(String addr) { this.addr = addr; } + public String getAddr() { + return addr; + } + public void setPort(int port) { this.port = port; } + public int getPort() { + return port; + } + public void buildOdpTable(String tenantName, String fullUserName, String password, - String database, ObTableClient.RunningMode runningMode, Properties properties, - Map tableConfigs) throws Exception { + String database, ObTableClient.RunningMode runningMode, + Properties properties, Map tableConfigs) + throws Exception { this.obTable = new ObTable.Builder(addr, port) // - .setLoginInfo(tenantName, fullUserName, password, database, ObTableClientType.JAVA_TABLE_CLIENT) // - .setProperties(properties).setConfigs(tableConfigs).setIsOdpMode(true).build(); + .setLoginInfo(tenantName, fullUserName, password, database, + ObTableClientType.JAVA_TABLE_CLIENT) // + .setProperties(properties).setConfigs(tableConfigs).setIsOdpMode(true).build(); if (ObGlobal.isDistributedExecSupport() && runningMode == ObTableClient.RunningMode.HBASE) { // support distributed execute, login again this.obTable = new ObTable.Builder(addr, port) - .setLoginInfo(tenantName, fullUserName, password, database, ObTableClientType.JAVA_HBASE_CLIENT) - .setProperties(properties).setConfigs(tableConfigs).setIsOdpMode(true).build(); + .setLoginInfo(tenantName, fullUserName, password, database, + ObTableClientType.JAVA_HBASE_CLIENT).setProperties(properties) + .setConfigs(tableConfigs).setIsOdpMode(true).build(); } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/ReplicaLocation.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/ReplicaLocation.java index 8936b029..fdb1d3e1 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/ReplicaLocation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/ReplicaLocation.java @@ -116,6 +116,13 @@ public String getIp() { return addr.getIp(); } + /* + * Get svr port of the replica. + */ + public int getSvrPort() { + return addr.getSvrPort(); + } + /* * To string. */ diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/RouteTableRefresher.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/RouteTableRefresher.java index 9c15268b..1755ca2c 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/RouteTableRefresher.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/RouteTableRefresher.java @@ -116,12 +116,6 @@ private void doRsListCheck() { } } if (needRefresh) { - newConfigServer = LocationUtil.refreshIDC2RegionMapFroConfigServerInfo( - newConfigServer, tableClient.getParamURL(), - tableClient.getRsListAcquireConnectTimeout(), - tableClient.getRsListAcquireReadTimeout(), - tableClient.getRsListAcquireTryTimes(), - tableClient.getRsListAcquireRetryInterval()); tableRoute.setConfigServerInfo(newConfigServer); tableRoute.refreshRosterByRsList(newRsList); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableLocations.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableLocations.java index 8c47a6c1..16b55de0 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableLocations.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableLocations.java @@ -267,7 +267,9 @@ private TableEntry refreshTableEntry(TableEntry tableEntry, String tableName, } } // prepare the table entry for weak read. - tableEntry.prepareForWeakRead(serverRoster.getServerLdcLocation()); + if (serverRoster.getServerLdcLocation() != null && serverRoster.getServerLdcLocation().isLdcUsed()) { + tableEntry.prepareForWeakRead(serverRoster.getServerLdcLocation()); + } locations.put(tableName, tableEntry); tableEntryRefreshContinuousFailureCount.set(0); if (logger.isDebugEnabled()) { @@ -392,7 +394,9 @@ public TableEntry refreshPartitionLocation(TableEntry tableEntry, String tableNa throw t; } } // end while - tableEntry.prepareForWeakRead(serverRoster.getServerLdcLocation()); + if (serverRoster.getServerLdcLocation() != null && serverRoster.getServerLdcLocation().isLdcUsed()) { + tableEntry.prepareForWeakRead(serverRoster.getServerLdcLocation()); + } locations.put(tableName, tableEntry); tableEntryRefreshContinuousFailureCount.set(0); return tableEntry; @@ -519,7 +523,9 @@ public TableEntry refreshTabletLocationBatch(TableEntry tableEntry, String table throw t; } } // end while - tableEntry.prepareForWeakRead(serverRoster.getServerLdcLocation()); + if (serverRoster.getServerLdcLocation() != null && serverRoster.getServerLdcLocation().isLdcUsed()) { + tableEntry.prepareForWeakRead(serverRoster.getServerLdcLocation()); + } locations.put(tableName, tableEntry); tableEntryRefreshContinuousFailureCount.set(0); return tableEntry; diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java index d39eddfa..520c5225 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java @@ -25,6 +25,7 @@ import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObRowKey; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObBorderFlag; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObNewRange; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQuery; @@ -48,33 +49,57 @@ import static java.lang.String.format; public class TableRoute { - private static final Logger logger = getLogger(TableRoute.class); - private static final ObjectMapper objectMapper = new ObjectMapper(); + private static final Logger logger = getLogger(TableRoute.class); + private static final ObjectMapper objectMapper = new ObjectMapper(); private final ObTableClient tableClient; - private final ObUserAuth sysUA; // user and password to access route table - private final ServerRoster serverRoster = new ServerRoster(); // all servers which contain current tenant - private long clusterVersion = -1; - private volatile long lastRefreshMetadataTimestamp; - private volatile ConfigServerInfo configServerInfo = new ConfigServerInfo(); // rslist and IDC - private volatile TableRoster tableRoster = new TableRoster(); // table mean connection pool here - private TableLocations tableLocations = null; // map[tableName, TableEntry] - private TableLocations odpTableLocations = null; // for parition handle - private IndexLocations indexLocations = null; // global index location - private TableGroupCache tableGroupCache = null; - private OdpInfo odpInfo = null; - private RouteTableRefresher routeRefresher = null; - - public final Lock refreshTableRosterLock = new ReentrantLock(); + private final ObUserAuth sysUA; // user and password to access route table + private volatile ServerRoster serverRoster = null; // all servers which contain current tenant + private volatile ConfigServerInfo configServerInfo = null; // rslist + private volatile TableRoster tableRoster = null; // table mean connection pool here + private ObTableConsistencyLevel consistencyLevel = ObTableConsistencyLevel.STRONG; // global read consistency level + private String currentIDC = null; // current client IDC for weak read routing + private ObRoutePolicy routePolicy = ObRoutePolicy.FOLLOWER_FIRST; // route policy for weak read + private TableLocations tableLocations = null; // map[tableName, TableEntry] + private TableLocations odpTableLocations = null; // for parition handle + private IndexLocations indexLocations = null; // global index location + private TableGroupCache tableGroupCache = null; + private OdpInfo odpInfo = null; + private RouteTableRefresher routeRefresher = null; + private long lastRefreshMetadataTimestamp = -1; + public final Lock refreshTableRosterLock = new ReentrantLock(); public TableRoute(ObTableClient tableClient, ObUserAuth sysUA) { this.tableClient = tableClient; this.sysUA = sysUA; + } + + public void init() throws Exception { + BOOT.info("init TableRoute"); if (tableClient.isOdpMode()) { + BOOT.info("init TableRoute in ODP mode"); odpTableLocations = new TableLocations(tableClient); + try { + buildOdpInfo(tableClient.getOdpAddr(), tableClient.getOdpPort(), + tableClient.getRunningMode()); + } catch (Exception e) { + logger + .warn( + "The addr{}:{} failed to put into table roster, the node status may be wrong, Ignore", + tableClient.getOdpAddr(), tableClient.getOdpPort()); + throw new RuntimeException(e); + } } else { + BOOT.info("init TableRoute in direct mode"); tableLocations = new TableLocations(tableClient); indexLocations = new IndexLocations(tableClient); tableGroupCache = new TableGroupCache(tableClient); + tableRoster = new TableRoster(); + serverRoster = new ServerRoster(); + loadConfigServerInfo(); // build ConfigServerInfo to get rsList + TableEntryKey rootServerKey = new TableEntryKey(tableClient.getClusterName(), + tableClient.getTenantName(), OCEANBASE_DATABASE, ALL_DUMMY_TABLE); + initRoster(rootServerKey, false, tableClient.getRunningMode()); // build tableRoster and ServerRoster + launchRouteRefresher(); // create background refresh-checker task } } @@ -83,6 +108,62 @@ public void close() throws ObTableCloseException { routeRefresher.close(); } tableRoster.closeRoster(); + ObTable odpTable = getOdpTable(); + if (odpTable != null) { + odpTable.close(); + } + } + + /** + * Set current IDC for weak read routing. + * @param idc idc + */ + public void setCurrentIDC(String idc) { + this.currentIDC = idc; + } + + /** + * Get current IDC. + * @return current IDC + */ + public String getCurrentIDC() { + return this.currentIDC; + } + + /** + * Set router policy for weak read. + * @param policy route policy + */ + public void setRoutePolicy(ObRoutePolicy policy) { + this.routePolicy = policy; + } + + /** + * Get router policy. + * @return route policy + */ + public ObRoutePolicy getRoutePolicy() { + return this.routePolicy; + } + + /** + * Get read consistency level. + * @return read consistency level + */ + public ObTableConsistencyLevel getReadConsistency() { + return this.consistencyLevel; + } + + /** + * Set read consistency level. + * @param readConsistency read consistency level + */ + public void setReadConsistency(String readConsistency) throws IllegalArgumentException { + this.consistencyLevel = ObTableConsistencyLevel.getByName(readConsistency); + } + + public OdpInfo getOdpInfo() { + return odpInfo; } public void setConfigServerInfo(ConfigServerInfo configServerInfo) { @@ -168,7 +249,7 @@ public ObTableServerCapacity getServerCapacity() { } public void buildOdpInfo(String odpAddr, int odpPort, ObTableClient.RunningMode runningMode) - throws Exception { + throws Exception { this.odpInfo = new OdpInfo(odpAddr, odpPort); this.odpInfo.buildOdpTable(tableClient.getTenantName(), tableClient.getFullUserName(), tableClient.getPassword(), tableClient.getDatabase(), runningMode, @@ -179,6 +260,8 @@ public void buildOdpInfo(String odpAddr, int odpPort, ObTableClient.RunningMode * load rsList from rootService * */ public ConfigServerInfo loadConfigServerInfo() throws Exception { + BOOT.info("load config server info from paramURL: {}, dataSourceName: {}", + tableClient.getParamURL(), tableClient.getDataSourceName()); this.configServerInfo = LocationUtil.loadConfigServerInfo(tableClient.getParamURL(), tableClient.getDataSourceName(), tableClient.getRsListAcquireConnectTimeout(), tableClient.getRsListAcquireReadTimeout(), tableClient.getRsListAcquireTryTimes(), @@ -193,12 +276,15 @@ public ConfigServerInfo loadConfigServerInfo() throws Exception { * */ public void initRoster(TableEntryKey rootServerKey, boolean initialized, ObTableClient.RunningMode runningMode) throws Exception { + BOOT.info( + "init tableRoster and serverRoster for rootServerKey: {}, initialized: {}, runningMode: {}", + rootServerKey, initialized, runningMode); List servers = new ArrayList(); ConcurrentHashMap addr2Table = new ConcurrentHashMap(); List rsList = configServerInfo.getRsList(); - BOOT.info("{} success to get rsList, paramURL: {}, rsList: {},idc2Region: {}", - tableClient.getDatabase(), configServerInfo.getParamURL(), objectMapper.writeValueAsString(rsList), - objectMapper.writeValueAsString(configServerInfo.getIdc2Region())); + BOOT.info("{} success to get rsList, paramURL: {}, rsList: {}", + tableClient.getDatabase(), configServerInfo.getParamURL(), + objectMapper.writeValueAsString(rsList)); TableEntry tableEntry = null; int retryMaxTimes = rsList.size(); @@ -233,10 +319,14 @@ public void initRoster(TableEntryKey rootServerKey, boolean initialized, rootServerKey, rsList); throw new ObTableUnexpectedException("all rs servers are not available", exception); } + if (tableEntry == null) { + BOOT.error("tableEntry is null, rootServerKey:{}, rsList: {}", rootServerKey, rsList); + throw new ObTableUnexpectedException("tableEntry is null"); + } List replicaLocations = tableEntry.getTableLocation() .getReplicaLocations(); BOOT.info("{} success to get replicaLocation {}", tableClient.getDatabase(), - objectMapper.writeValueAsString(replicaLocations)); + objectMapper.writeValueAsString(replicaLocations)); for (ReplicaLocation replicaLocation : replicaLocations) { ObServerInfo info = replicaLocation.getInfo(); @@ -272,12 +362,9 @@ public void initRoster(TableEntryKey rootServerKey, boolean initialized, this.serverRoster.reset(servers); // Get Server LDC info for weak read consistency. - if (StringUtil.isEmpty(tableClient.getCurrentIDC())) { - tableClient.setCurrentIDC(ZoneUtil.getCurrentIDC()); + if (StringUtil.isEmpty(this.currentIDC)) { + this.currentIDC = ZoneUtil.getCurrentIDC(); } - String regionFromOcp = configServerInfo.getIdc2Region(tableClient.getCurrentIDC()); - BOOT.info("{} success get currentIDC {}, regionFromOcp {}", tableClient.getDatabase(), - tableClient.getCurrentIDC(), regionFromOcp); success = false; retryMaxTimes = servers.size(); @@ -305,8 +392,7 @@ public void initRoster(TableEntryKey rootServerKey, boolean initialized, rootServerKey.getTenantName(), rsList); throw new ObTableUnexpectedException("all tenant servers are not available"); } - this.serverRoster.resetServerLdc(ObServerLdcLocation.buildLdcLocation(ldcServers, - tableClient.getCurrentIDC(), regionFromOcp)); + this.serverRoster.resetServerLdc(ObServerLdcLocation.buildLdcLocation(ldcServers, this.currentIDC)); if (BOOT.isInfoEnabled()) { BOOT.info("{} finish refresh serverRoster: {}", tableClient.getDatabase(), objectMapper.writeValueAsString(serverRoster)); @@ -419,9 +505,7 @@ public void refreshRosterByRsList(List newRsList) throws Exception } // 3. reset Server LDC location. - String regionFromOcp = configServerInfo.getIdc2Region(tableClient.getCurrentIDC()); - serverRoster.resetServerLdc(ObServerLdcLocation.buildLdcLocation(ldcServers, - tableClient.getCurrentIDC(), regionFromOcp)); + serverRoster.resetServerLdc(ObServerLdcLocation.buildLdcLocation(ldcServers, this.currentIDC)); if (logger.isInfoEnabled()) { logger.info("finish refresh serverRoster: {}, servers num: {}", @@ -522,7 +606,7 @@ public TableEntry refreshPartitionLocation(String tableName, long tabletId, Tabl try { tableEntry = tableLocations.refreshPartitionLocation(tableEntry, tableName, tabletId, serverRoster, sysUA); - validCachedObTableStatus(tableName, tableEntry, tabletId, tableClient.getRoute(false)); + validCachedObTableStatus(tableName, tableEntry, tabletId); return tableEntry; } catch (ObTableGetException e) { logger @@ -531,9 +615,9 @@ public TableEntry refreshPartitionLocation(String tableName, long tabletId, Tabl tableName); if (e.getMessage().contains("Need to fetch meta")) { tableEntry = refreshMeta(tableName); - tableEntry = tableLocations.refreshPartitionLocation(tableEntry, tableName, tabletId, - serverRoster, sysUA); - validCachedObTableStatus(tableName, tableEntry, tabletId, tableClient.getRoute(false)); + tableEntry = tableLocations.refreshPartitionLocation(tableEntry, tableName, + tabletId, serverRoster, sysUA); + validCachedObTableStatus(tableName, tableEntry, tabletId); return tableEntry; } throw e; @@ -552,7 +636,7 @@ public TableEntry refreshTabletLocationBatch(String tableName) throws Exception serverRoster, sysUA); Long[] tablets = getTabletsFromTableEntry(tableEntry); for (long tablet : tablets) { - validCachedObTableStatus(tableName, tableEntry, tablet, tableClient.getRoute(false)); + validCachedObTableStatus(tableName, tableEntry, tablet); } return tableEntry; } catch (ObTableGetException e) { @@ -566,27 +650,31 @@ public TableEntry refreshTabletLocationBatch(String tableName) throws Exception serverRoster, sysUA); Long[] tablets = getTabletsFromTableEntry(tableEntry); for (long tablet : tablets) { - validCachedObTableStatus(tableName, tableEntry, tablet, tableClient.getRoute(false)); + validCachedObTableStatus(tableName, tableEntry, tablet); } return tableEntry; } throw e; } catch (Throwable t) { logger.error( - "refresh location in batch meets exception, tableName: {}, error message: {}", - tableName, t.getMessage()); + "refresh location in batch meets exception, tableName: {}, error message: {}", + tableName, t.getMessage()); throw t; } } - public Map refreshTabletLocationAndGetPartIdMap(String tableName, ObTableQuery query, boolean isHKV) throws Exception { - Map partIdParamMap = getPartIdParamMapForQuery(tableName, query.getScanRangeColumns(), query.getKeyRanges()); + public Map refreshTabletLocationAndGetPartIdMap(String tableName, + ObTableQuery query, + boolean isHKV) + throws Exception { + Map partIdParamMap = getPartIdParamMapForQuery(tableName, + query.getScanRangeColumns(), query.getKeyRanges()); if (isHKV) { // for HBase process, if distributed function is enabled, no need to do routing refresh boolean isDistributedSupported = getServerCapacity().isSupportDistributedExecute(); if (partIdParamMap.size() > 1 && !isDistributedSupported) { throw new ObTablePartitionConsistentException( - "query and mutate must be a atomic operation"); + "query and mutate must be a atomic operation"); } else if (isDistributedSupported) { // do nothing } @@ -595,7 +683,7 @@ public Map refreshTabletLocationAndGetPartIdMap(String table // for now only support to query single tablet if (partIdParamMap.size() > 1) { throw new ObTablePartitionConsistentException( - "query and mutate must be a atomic operation"); + "query and mutate must be a atomic operation"); } else if (partIdParamMap.isEmpty()) { throw new ObTableException("could not find part id of range"); } @@ -611,27 +699,39 @@ private Long[] getTabletsFromTableEntry(TableEntry tableEntry) { Long[] tablets = null; if (tableEntry.isPartitionTable()) { tablets = tableEntry.getPartitionInfo().getPartTabletIdMap().values() - .toArray(new Long[0]); + .toArray(new Long[0]); } else { - tablets = new Long[]{0L}; + tablets = new Long[] { 0L }; } return tablets; } - private void validCachedObTableStatus(String tableName, TableEntry tableEntry, long tabletId, ObServerRoute route) throws Exception { - ObPartitionLocationInfo obPartitionLocationInfo = getOrRefreshPartitionInfo(tableEntry, tableName, tabletId); + private void validCachedObTableStatus(String tableName, TableEntry tableEntry, long tabletId) + throws Exception { + ObPartitionLocationInfo obPartitionLocationInfo = getOrRefreshPartitionInfo(tableEntry, + tableName, tabletId); if (obPartitionLocationInfo.getPartitionLocation() == null) { throw new ObTableNotExistException( - "partition location is null after refresh, table: { " + tableName - + " } may not exist"); + "partition location is null after refresh, table: { " + tableName + + " } may not exist"); } - ReplicaLocation replica = getPartitionLocation(obPartitionLocationInfo, route); - ObServerAddr addr = replica.getAddr(); + + ReplicaLocation leader = obPartitionLocationInfo.getPartitionLocation().getLeader(); + ObServerAddr addr = leader.getAddr(); ObTable obTable = tableRoster.getTable(addr); if (obTable != null && !obTable.isValid()) { obTable.setValid(); } + + for (ReplicaLocation replica : obPartitionLocationInfo.getPartitionLocation().getReplicas()) { + ObServerAddr replicaAddr = replica.getAddr(); + ObTable replicaObTable = tableRoster.getTable(replicaAddr); + if (replicaObTable != null && !replicaObTable.isValid()) { + replicaObTable.setValid(); + } + } } + /** * get TableParam by tableName and rowkey * @param tableName tableName @@ -639,28 +739,29 @@ private void validCachedObTableStatus(String tableName, TableEntry tableEntry, l * @return ObTableParam tableParam * */ public ObTableParam getTableParam(String tableName, Row rowkey) throws Exception { - ObServerRoute route = tableClient.getRoute(false); - return getTableParamWithRoute(tableName, rowkey, route); + return getTableParam(tableName, rowkey, null); } - public ObTableParam getTableParamWithRoute(String tableName, Row rowkey, ObServerRoute route) - throws Exception { + public ObTableParam getTableParam(String tableName, Row rowkey, + ObTableConsistencyLevel currentConsistencyLevel) + throws Exception { TableEntry tableEntry = getTableEntry(tableName); if (tableEntry == null) { logger.error("tableEntry is null, tableName: {}", tableName); throw new ObTableEntryRefreshException("tableEntry is null, tableName: " + tableName); } long partId = getPartId(tableEntry, rowkey); - return getTableInternal(tableName, tableEntry, partId, route); + return getTableInternal(tableName, tableEntry, partId, currentConsistencyLevel); } /** * get TableParam by tableName and rowkeys in batch * @param tableName tableName * @param rowkeys list of row key or partition key names and values + * @param currentConsistencyLevel current consistency level * @return ObTableParam tableParam * */ - public List getTableParams(String tableName, List rowkeys) throws Exception { + public List getTableParams(String tableName, List rowkeys, ObTableConsistencyLevel currentConsistencyLevel) throws Exception { TableEntry tableEntry = getTableEntry(tableName); if (tableEntry == null) { logger.error("tableEntry is null, tableName: {}", tableName); @@ -668,11 +769,10 @@ public List getTableParams(String tableName, List rowkeys) th } List params = new ArrayList<>(); - ObServerRoute route = tableClient.getRoute(false); for (Row rowkey : rowkeys) { long partId = getPartId(tableEntry, rowkey); ObTableParam param = null; - param = getTableInternal(tableName, tableEntry, partId, route); + param = getTableInternal(tableName, tableEntry, partId, currentConsistencyLevel); params.add(param); } return params; @@ -720,8 +820,10 @@ private ObPartitionLocationInfo getOrRefreshPartitionInfo(TableEntry tableEntry, return obPartitionLocationInfo; } - public Map getPartIdParamMapForQuery(String tableName, List scanRangeColumns, - List keyRanges) throws Exception { + public Map getPartIdParamMapForQuery(String tableName, + List scanRangeColumns, + List keyRanges) + throws Exception { Map parIdParamMapObTable = new HashMap(); for (ObNewRange keyRange : keyRanges) { ObRowKey startKey = keyRange.getStartKey(); @@ -748,9 +850,9 @@ public Map getPartIdParamMapForQuery(String tableName, List< } } ObBorderFlag borderFlag = keyRange.getBorderFlag(); + // route parameter is kept for backward compatibility but not used List paramList = getTablesInternal(tableName, scanRangeColumns, start, - borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd(), - tableClient.getRoute(false)); + borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd(), null); for (ObTableParam param : paramList) { parIdParamMapObTable.put(param.getPartId(), param); } @@ -762,14 +864,16 @@ public Map getPartIdParamMapForQuery(String tableName, List< * get addr by partId * @param tableName table want to get * @param partId tabletId of table (real tablet id in 4.x) - * @param route ObServer route + * @param currentConsistencyLevel current consistency level * @return ObTableParam table information for execution * @throws Exception exception */ - public ObTableParam getTableWithPartId(String tableName, long partId, ObServerRoute route) - throws Exception { + public ObTableParam getTableWithPartId(String tableName, long partId, + ObTableConsistencyLevel currentConsistencyLevel) + throws Exception { + // route parameter is kept for backward compatibility but not used TableEntry tableEntry = getTableEntry(tableName); - return getTableInternal(tableName, tableEntry, partId, route); + return getTableInternal(tableName, tableEntry, partId, currentConsistencyLevel); } /** @@ -777,12 +881,13 @@ public ObTableParam getTableWithPartId(String tableName, long partId, ObServerRo * @param tableName table want to get * @param tableEntry tableEntry * @param partId logicId of tablet - * @param route ObServer route + * @param currentConsistencyLevel current consistency level * @return ObTableParam table information for execution * @throws Exception exception */ private ObTableParam getTableInternal(String tableName, TableEntry tableEntry, long partId, - ObServerRoute route) throws Exception { + ObTableConsistencyLevel currentConsistencyLevel) + throws Exception { ReplicaLocation replica = null; long tabletId = getTabletIdByPartId(tableEntry, partId); ObPartitionLocationInfo obPartitionLocationInfo = null; @@ -792,7 +897,7 @@ private ObTableParam getTableInternal(String tableName, TableEntry tableEntry, l "partition location is null after refresh, table: { " + tableName + " } may not exist"); } - replica = getPartitionLocation(obPartitionLocationInfo, route); + replica = getPartitionLocation(obPartitionLocationInfo, currentConsistencyLevel); /** * Normally, getOrRefreshPartitionInfo makes sure that a thread only continues if it finds the leader * during a route refresh. But sometimes, there might not be a leader yet. In this case, the thread @@ -821,13 +926,14 @@ private ObTableParam getTableInternal(String tableName, TableEntry tableEntry, l tableClient.syncRefreshMetadata(true); // the addr is wrong, need to refresh location if (logger.isInfoEnabled()) { - logger.info("Cannot get ObTable by addr {}, refreshing metadata, tryTimes: {}.", addr, retryTimes); + logger.info("Cannot get ObTable by addr {}, refreshing metadata, tryTimes: {}.", + addr, retryTimes); } // refresh tablet location based on the latest roster, in case that some of the observers have been killed // and used the old location tableEntry = refreshPartitionLocation(tableName, tabletId, tableEntry); obPartitionLocationInfo = getOrRefreshPartitionInfo(tableEntry, tableName, tabletId); - replica = getPartitionLocation(obPartitionLocationInfo, route); + replica = getPartitionLocation(obPartitionLocationInfo, currentConsistencyLevel); if (replica == null) { RUNTIME.error("Cannot get replica by tabletId: " + tabletId); @@ -847,9 +953,16 @@ private ObTableParam getTableInternal(String tableName, TableEntry tableEntry, l return param; } - private ReplicaLocation getPartitionLocation(ObPartitionLocationInfo obPartitionLocationInfo, - ObServerRoute route) { - return obPartitionLocationInfo.getPartitionLocation().getReplica(route); + private ReplicaLocation getPartitionLocation(ObPartitionLocationInfo locationInfo, + ObTableConsistencyLevel currentConsistencyLevel) + throws ObTableException { + ObPartitionLocation partitionLocation = locationInfo.getPartitionLocation(); + ObTableConsistencyLevel level = currentConsistencyLevel; + // when currentConsistencyLevel is null, we use global consistencyLevel + if (level == null) { + level = this.consistencyLevel; + } + return partitionLocation.getReplica(level, routePolicy); } private ObTableParam createTableParam(ObTable obTable, TableEntry tableEntry, @@ -878,7 +991,9 @@ private ObTableParam createTableParam(ObTable obTable, TableEntry tableEntry, * @throws Exception exception */ public ObTableParam getTableParam(String tableName, List scanRangeColumns, - ObNewRange keyRange) throws Exception { + ObNewRange keyRange, + ObTableConsistencyLevel currentConsistencyLevel) + throws Exception { Map tabletIdIdMapObTable = new HashMap(); ObRowKey startKey = keyRange.getStartKey(); int startKeySize = startKey.getObjs().size(); @@ -904,9 +1019,10 @@ public ObTableParam getTableParam(String tableName, List scanRangeColumn } } ObBorderFlag borderFlag = keyRange.getBorderFlag(); + // route parameter is kept for backward compatibility but not used List paramList = getTablesInternal(tableName, scanRangeColumns, start, borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd(), - tableClient.getRoute(false)); + currentConsistencyLevel); for (ObTableParam param : paramList) { tabletIdIdMapObTable.put(param.getTabletId(), param); } @@ -933,9 +1049,11 @@ public ObTableParam getTableParam(String tableName, List scanRangeColumn * @throws Exception exception */ public ObTableParam getTableParam(String tableName, List scanRangeColumns, - List keyRanges) throws Exception { - Map partIdIdMapObTable = getPartIdParamMapForQuery( - tableName, scanRangeColumns, keyRanges); + List keyRanges, + ObTableConsistencyLevel currentConsistencyLevel) + throws Exception { + Map partIdIdMapObTable = getPartIdParamMapForQuery(tableName, + scanRangeColumns, keyRanges); // for now only support to query single tablet if (partIdIdMapObTable.size() > 1) { throw new ObTablePartitionConsistentException( @@ -962,15 +1080,19 @@ public ObTableParam getTableParam(String tableName, List scanRangeColumn */ public List getTableParams(String tableName, ObTableQuery query, Object[] start, boolean startInclusive, Object[] end, - boolean endInclusive) throws Exception { + boolean endInclusive, + ObTableConsistencyLevel currentConsistencyLevel) + throws Exception { + // route parameter is kept for backward compatibility but not used return getTablesInternal(tableName, query.getScanRangeColumns(), start, startInclusive, - end, endInclusive, tableClient.getRoute(false)); + end, endInclusive, currentConsistencyLevel); } private List getTablesInternal(String tableName, List scanRangeColumns, Object[] start, boolean startInclusive, Object[] end, boolean endInclusive, - ObServerRoute route) throws Exception { + ObTableConsistencyLevel currentConsistencyLevel) throws Exception { + // route parameter is kept for backward compatibility but not used if (start.length != end.length) { throw new IllegalArgumentException("length of start key and end key is not equal"); } @@ -1007,12 +1129,12 @@ private List getTablesInternal(String tableName, List scan } // List> partIdWithReplicaList = getPartitionReplica(tableEntry, tableName, - startRow, startInclusive, endRow, endInclusive, route); + startRow, startInclusive, endRow, endInclusive, currentConsistencyLevel); List params = new ArrayList<>(); for (ObPair partIdWithReplica : partIdWithReplicaList) { long partId = partIdWithReplica.getLeft(); - ObTableParam param = getTableInternal(tableName, tableEntry, partId, route); + ObTableParam param = getTableInternal(tableName, tableEntry, partId, currentConsistencyLevel); params.add(param); } return params; @@ -1035,7 +1157,8 @@ private List> getPartitionReplica(TableEntry table boolean startIncluded, Row endRow, boolean endIncluded, - ObServerRoute route) throws Exception { + ObTableConsistencyLevel currentConsistencyLevel) throws Exception { + // route parameter is kept for backward compatibility but not used List> replicas = new ArrayList<>(); List partIds = getPartIds(tableEntry, startRow, startIncluded, endRow, endIncluded); @@ -1045,7 +1168,7 @@ private List> getPartitionReplica(TableEntry table if (locationInfo.getPartitionLocation() == null) { throw new ObTableNotExistException("partition location is null after refresh, table: { " + tableName + " } may not exist"); } - replicas.add(new ObPair<>(partId, getPartitionLocation(locationInfo, route))); + replicas.add(new ObPair<>(partId, getPartitionLocation(locationInfo, currentConsistencyLevel))); } return replicas; @@ -1166,8 +1289,7 @@ public ObTableParam getOdpTableParam(String tableName, Row rowkey) throws Except * @return ObTableParam table information for execution * @throws Exception exception */ - public ObTableParam getOdpTableWithPartId(String tableName, long partId) - throws Exception { + public ObTableParam getOdpTableWithPartId(String tableName, long partId) throws Exception { TableEntry tableEntry = getOdpTableEntry(tableName); return getOdpTableInternal(tableEntry, partId); } @@ -1203,18 +1325,19 @@ private ObTableParam getOdpTableInternal(TableEntry odpTableEntry, long partId) * @return list of table obTableParams * @throws Exception exception */ - public List getOdpTableParams(String tableName, ObTableQuery query, Object[] start, - boolean startInclusive, Object[] end, - boolean endInclusive) throws Exception { + public List getOdpTableParams(String tableName, ObTableQuery query, + Object[] start, boolean startInclusive, + Object[] end, boolean endInclusive) + throws Exception { - return getOdpTablesInternal(tableName, query.getScanRangeColumns(), start, - startInclusive, end, endInclusive); + return getOdpTablesInternal(tableName, query.getScanRangeColumns(), start, startInclusive, + end, endInclusive); } - private List getOdpTablesInternal(String tableName, List scanRangeColumns, - Object[] start, boolean startInclusive, - Object[] end, boolean endInclusive) - throws Exception { + private List getOdpTablesInternal(String tableName, + List scanRangeColumns, Object[] start, + boolean startInclusive, Object[] end, + boolean endInclusive) throws Exception { if (start.length != end.length) { throw new IllegalArgumentException("length of start key and end key is not equal"); } @@ -1233,18 +1356,18 @@ private List getOdpTablesInternal(String tableName, List s Row endRow = new Row(); // ensure the format of column names and values if the current table is a table with partition if (odpTableEntry.isPartitionTable() - && odpTableEntry.getPartitionInfo().getLevel() != ObPartitionLevel.LEVEL_ZERO) { + && odpTableEntry.getPartitionInfo().getLevel() != ObPartitionLevel.LEVEL_ZERO) { if ((scanRangeColumns == null || scanRangeColumns.isEmpty()) && start.length == 1 - && start[0] instanceof ObObj && ((ObObj) start[0]).isMinObj() && end.length == 1 - && end[0] instanceof ObObj && ((ObObj) end[0]).isMaxObj()) { + && start[0] instanceof ObObj && ((ObObj) start[0]).isMinObj() && end.length == 1 + && end[0] instanceof ObObj && ((ObObj) end[0]).isMaxObj()) { // for getPartition to query all partitions scanRangeColumns = new ArrayList(Collections.nCopies(start.length, - "partition")); + "partition")); } // scanRangeColumn may be longer than start/end in prefix scanning situation if (scanRangeColumns == null || scanRangeColumns.size() < start.length) { throw new IllegalArgumentException( - "length of key and scan range columns do not match, please use addRowKeyElement or set scan range columns"); + "length of key and scan range columns do not match, please use addRowKeyElement or set scan range columns"); } for (int i = 0; i < start.length; i++) { startRow.add(scanRangeColumns.get(i), start[i]); @@ -1253,7 +1376,7 @@ private List getOdpTablesInternal(String tableName, List s } List partIds = getPartIds(odpTableEntry, startRow, startInclusive, endRow, - endInclusive); + endInclusive); for (Long partId : partIds) { ObTable obTable = odpInfo.getObTable(); ObTableParam param = new ObTableParam(obTable); @@ -1302,4 +1425,4 @@ public ConcurrentHashMap getTableGroupInverted() { public ConcurrentHashMap getTableGroupCache() { return tableGroupCache.getTableGroupCache(); } -} \ No newline at end of file +} diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionEntry.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionEntry.java index 9e33eeae..b7709b0c 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionEntry.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionEntry.java @@ -34,8 +34,6 @@ public class ObPartitionEntry { private volatile Long lastRefreshAllTime = 0L; - private Map partitionLocation = new HashMap(); - // mapping from tablet id to ls id, and the part id to tablet id mapping is in ObPartitionInfo private Map tabletLsIdMap = new HashMap<>(); @@ -58,16 +56,6 @@ public void removeNonExistentTablet(Map partTabletMap) { } } - public void removePartitionLocationInfoByLsId(long lsId) { - int cnt = 0; - for (Map.Entry entry : partitionInfos.entrySet()) { - if (entry.getValue().getTabletLsId() == lsId) { - ++cnt; - partitionInfos.remove(entry.getKey()); - } - } - } - public long getLastRefreshAllTime() { return lastRefreshAllTime; } @@ -75,17 +63,6 @@ public long getLastRefreshAllTime() { public void setLastRefreshAllTime(long time) { lastRefreshAllTime = time; } - - public Map getPartitionLocation() { - return partitionLocation; - } - - /* - * Set partition location. - */ - public void setPartitionLocation(Map partitionLocation) { - this.partitionLocation = partitionLocation; - } public Map getTabletLsIdMap() { return tabletLsIdMap; @@ -96,44 +73,14 @@ public void setTabletLsIdMap(Map tabletLsIdMap) { } public long getLsId(long tabletId) { return tabletLsIdMap.get(tabletId); } - - /* - * Get partition location with part id. - */ - public ObPartitionLocation getPartitionLocationWithPartId(long partId) { - return partitionLocation.get(partId); - } - - /* - * Get partition location with tablet id. - */ - public ObPartitionLocation getPartitionLocationWithTabletId(long tabletId) { - return partitionLocation.get(tabletId); - } - - /* - * Put partition location with part id. - */ - public ObPartitionLocation putPartitionLocationWithPartId(long partId, - ObPartitionLocation ObpartitionLocation) { - return partitionLocation.put(partId, ObpartitionLocation); - } - - /* - * Put partition location with part id. - */ - public ObPartitionLocation putPartitionLocationWithTabletId(long tabletId, - ObPartitionLocation ObpartitionLocation) { - return partitionLocation.put(tabletId, ObpartitionLocation); - } /* * Prepare for weak read. * @param ldcLocation */ public void prepareForWeakRead(ObServerLdcLocation ldcLocation) { - for (Map.Entry entry : partitionLocation.entrySet()) { - entry.getValue().prepareForWeakRead(ldcLocation); + for (Map.Entry entry : partitionInfos.entrySet()) { + entry.getValue().getPartitionLocation().prepareForWeakRead(ldcLocation); } } @@ -142,6 +89,6 @@ public void prepareForWeakRead(ObServerLdcLocation ldcLocation) { */ @Override public String toString() { - return "ObPartitionEntry{" + "partitionLocation=" + partitionLocation + '}'; + return "ObPartitionEntry{" + "partitionInfos=" + partitionInfos + ", tabletLsIdMap=" + tabletLsIdMap + ", lastRefreshAllTime=" + lastRefreshAllTime + '}'; } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java index 9b4421ca..e2c6f754 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java @@ -17,8 +17,8 @@ package com.alipay.oceanbase.rpc.location.model.partition; -import com.alipay.oceanbase.rpc.exception.ObTablePartitionNoMasterException; import com.alipay.oceanbase.rpc.location.model.*; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; import java.util.ArrayList; import java.util.Collections; @@ -74,62 +74,55 @@ public void addReplicaLocation(ReplicaLocation replica) { * @param route * @return */ - public ReplicaLocation getReplica(ObServerRoute route) { + public ReplicaLocation getReplica(ObTableConsistencyLevel consistencyLevel, + ObRoutePolicy routePolicy) throws IllegalArgumentException { // strong read : read leader - if (route.getReadConsistency() == ObReadConsistency.STRONG) { + if (consistencyLevel == null || consistencyLevel == ObTableConsistencyLevel.STRONG) { return leader; } - // weak read by LDC - if (route.isLdcEnabled()) { - return getReadReplicaByLDC(route); - } else { - return getReadReplicaNoLdc(route); + // empty means not idc route + if (sameIdc.isEmpty() && sameRegion.isEmpty() && otherRegion.isEmpty()) { + return getReadReplicaNoLdc(routePolicy); } + + return getReadReplicaByRoutePolicy(routePolicy); } - /* - * Get read replica according to LDC route strategy. - * - * @param route - * @return - */ - public ReplicaLocation getReadReplicaByLDC(ObServerRoute route) { - if (route.getReadRoutePolicy() == ObRoutePolicy.FOLLOWER_FIRST) { - if (!route.isInBlackList(leader.getIp())) { - route.addToBlackList(leader.getIp()); + private ReplicaLocation getReadReplicaNoLdc(ObRoutePolicy routePolicy) { + for (ReplicaLocation r : replicas) { + if (r.isValid() && !r.isLeader()) { + return r; } } + if (routePolicy == ObRoutePolicy.FOLLOWER_ONLY) { + throw new IllegalArgumentException("No follower replica found for route policy: " + + routePolicy); + } + return leader; + } + + private ReplicaLocation getReadReplicaByRoutePolicy(ObRoutePolicy routePolicy) + throws IllegalArgumentException { for (ReplicaLocation r : sameIdc) { - if (!route.isInBlackList(r.getAddr().getIp())) { + if (r.isValid()) { return r; } } for (ReplicaLocation r : sameRegion) { - if (!route.isInBlackList(r.getAddr().getIp())) { + if (r.isValid()) { return r; } } for (ReplicaLocation r : otherRegion) { - if (!route.isInBlackList(r.getAddr().getIp())) { + if (r.isValid()) { return r; } } - return leader; - } - /* - * Get read replica according to LDC route strategy. - * - * @param route - * @return - */ - public ReplicaLocation getReadReplicaNoLdc(ObServerRoute route) { - for (ReplicaLocation r : replicas) { - if (!route.isInBlackList(r.getIp()) - && !(r.isLeader() && route.getReadRoutePolicy() == ObRoutePolicy.FOLLOWER_FIRST)) { - return r; - } + if (routePolicy == ObRoutePolicy.FOLLOWER_ONLY) { + throw new IllegalArgumentException("No follower replica found for route policy: " + + routePolicy); } return leader; } @@ -144,9 +137,9 @@ public void prepareForWeakRead(ObServerLdcLocation ldcLocation) { Collections.shuffle(replicas); if (ldcLocation != null && ldcLocation.isLdcUsed()) { for (ReplicaLocation replica : replicas) { - if (ldcLocation.inSameIDC(replica.getIp())) { + if (ldcLocation.inSameIDC(replica.getIp() + replica.getSvrPort())) { sameIdc.add(replica); - } else if (ldcLocation.inSameRegion(replica.getIp())) { + } else if (ldcLocation.inSameRegion(replica.getIp() + replica.getSvrPort())) { sameRegion.add(replica); } else { otherRegion.add(replica); diff --git a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java index ce5dde92..c6b58487 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java @@ -23,12 +23,11 @@ import com.alipay.oceanbase.rpc.exception.ObTableException; import com.alipay.oceanbase.rpc.get.Get; import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.OHOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableOperationType; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.mutate.ObTableQueryAndMutate; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQuery; import com.alipay.oceanbase.rpc.queryandmutate.QueryAndMutate; import com.alipay.oceanbase.rpc.table.ObTableClientLSBatchOpsImpl; import com.alipay.oceanbase.rpc.table.api.Table; @@ -318,6 +317,20 @@ private BatchOperationResult executeWithNormalBatchOp() throws Exception { return new BatchOperationResult(batchOps.executeWithResult()); } + private boolean checkReadConsistency(ObTableClient obTableClient, String readConsistency) throws IllegalArgumentException { + // 如果没有设置语句级别的 readConsistency(空串或null),使用 TableRoute 上的 consistencyLevel + if (readConsistency == null || readConsistency.isEmpty()) { + return obTableClient.getTableRoute().getReadConsistency() == ObTableConsistencyLevel.EVENTUAL; + } + if (readConsistency.equalsIgnoreCase("weak")) { + return true; + } else if (readConsistency.equalsIgnoreCase("strong")) { + return false; + } else { + throw new IllegalArgumentException("readConsistency is invalid: " + readConsistency); + } + } + private BatchOperationResult executeWithLSBatchOp() throws Exception { if (tableName == null || tableName.isEmpty()) { throw new IllegalArgumentException("table name is null"); @@ -325,9 +338,11 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { ObTableClientLSBatchOpsImpl batchOps; boolean hasSetRowkeyElement = false; int checkAndInsUpCnt = 0; + boolean isWeakRead = false; if (client instanceof ObTableClient) { - batchOps = new ObTableClientLSBatchOpsImpl(tableName, (ObTableClient) client); + ObTableClient obTableClient = (ObTableClient) client; + batchOps = new ObTableClientLSBatchOpsImpl(tableName, obTableClient); batchOps.setEntityType(entityType); batchOps.setServerCanRetry(serverCanRetry); batchOps.setNeedTabletId(needTabletId); @@ -339,19 +354,19 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { batchOps.addOperation(checkAndInsUp); List rowKeyNames = checkAndInsUp.getInsUp().getRowKeyNames(); if (!hasSetRowkeyElement && rowKeyNames != null) { - ((ObTableClient) client).addRowKeyElement(tableName, + obTableClient.addRowKeyElement(tableName, rowKeyNames.toArray(new String[0])); hasSetRowkeyElement = true; } } else if (operation instanceof Mutation) { Mutation mutation = (Mutation) operation; - if (((ObTableClient) client).getRunningMode() == ObTableClient.RunningMode.HBASE) { + if (obTableClient.getRunningMode() == ObTableClient.RunningMode.HBASE) { negateHbaseTimestamp(mutation); } batchOps.addOperation(mutation); if (!hasSetRowkeyElement && mutation.getRowKeyNames() != null) { List rowKeyNames = mutation.getRowKeyNames(); - ((ObTableClient) client).addRowKeyElement(tableName, + obTableClient.addRowKeyElement(tableName, rowKeyNames.toArray(new String[0])); hasSetRowkeyElement = true; } @@ -360,9 +375,11 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { if (get.getRowKey() == null) { throw new IllegalArgumentException("RowKey is null in Get operation"); } + isWeakRead = checkReadConsistency(obTableClient, get.getReadConsistency()); batchOps.addOperation(get); } else if (operation instanceof TableQuery) { TableQuery query = (TableQuery) operation; + isWeakRead = checkReadConsistency(obTableClient, query.getReadConsistency()); batchOps.addOperation(query); } else if (operation instanceof QueryAndMutate) { QueryAndMutate qm = (QueryAndMutate) operation; @@ -382,6 +399,11 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { "Can not mix checkAndInsUP and other types operation in batch"); } + boolean isMultiGet = isSameType + && (lastType == ObTableOperationType.GET || lastType == ObTableOperationType.SCAN); + if (isMultiGet) { + batchOps.setIsWeakRead(isWeakRead); + } batchOps.setReturningAffectedEntity(withResult); batchOps.setReturnOneResult(returnOneResult); batchOps.setAtomicOperation(isAtomic); diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java index b2056fa5..f6d84a6e 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java @@ -37,6 +37,16 @@ public enum ObTableConsistencyLevel { } } + public static ObTableConsistencyLevel getByName(String name) throws IllegalArgumentException { + if (name.equalsIgnoreCase("weak")) { + return EVENTUAL; + } else if (name.equalsIgnoreCase("strong")) { + return STRONG; + } else { + throw new IllegalArgumentException("readConsistency is invalid: " + name); + } + } + /* * Value of. */ diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java index ffe8697f..8c1c42c5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java @@ -21,8 +21,6 @@ import com.alipay.oceanbase.rpc.bolt.transport.ObTableConnection; import com.alipay.oceanbase.rpc.bolt.transport.TransportCodes; import com.alipay.oceanbase.rpc.exception.*; -import com.alipay.oceanbase.rpc.location.model.ObReadConsistency; -import com.alipay.oceanbase.rpc.location.model.ObServerRoute; import com.alipay.oceanbase.rpc.location.model.TableEntry; import com.alipay.oceanbase.rpc.location.model.partition.ObPair; import com.alipay.oceanbase.rpc.protocol.payload.AbstractPayload; @@ -67,7 +65,7 @@ public abstract class AbstractQueryStreamResult extends AbstractPayload implemen protected List cacheProperties = new LinkedList(); protected LinkedList> cacheRows = new LinkedList>(); private LinkedList, ObTableQueryResult>> partitionLastResult = new LinkedList, ObTableQueryResult>>(); - private ObReadConsistency readConsistency = ObReadConsistency.STRONG; + private ObTableConsistencyLevel readConsistency = ObTableConsistencyLevel.STRONG; // ObRowKey objs: [startKey, MIN_OBJECT, MIN_OBJECT] public List currentStartKey; protected ObTableClient client; @@ -118,7 +116,6 @@ protected ObPayload commonExecute(ObTableClient client, Logger logger, int tryTimes = 0; long startExecute = System.currentTimeMillis(); Set failedServerList = null; - ObServerRoute route = null; while (true) { client.checkStatus(); long currentExecute = System.currentTimeMillis(); @@ -138,20 +135,14 @@ protected ObPayload commonExecute(ObTableClient client, Logger logger, if (client.isOdpMode()) { subObTable = client.getOdpTable(); } else { - if (route == null) { - route = client.getReadRoute(); - } - if (failedServerList != null) { - route.setBlackList(failedServerList); - } if (needRefreshPartitionLocation) { // refresh partition TableEntry tableEntry = client.getOrRefreshTableEntry(indexTableName, false); client.refreshTableLocationByTabletId(indexTableName, client.getTabletIdByPartId(tableEntry, partIdWithIndex.getLeft())); - subObTable = client.getTableParamWithPartId(indexTableName, - partIdWithIndex.getRight().getTabletId(), route).getObTable(); + subObTable = client.getTableRoute().getTableWithPartId(indexTableName, + partIdWithIndex.getRight().getTabletId(), readConsistency).getObTable(); } } } @@ -437,8 +428,8 @@ protected Map> buildAllPartitions(ObTableClient } ObBorderFlag borderFlag = range.getBorderFlag(); - List params = client.getTableParams(indexTableName, - tableQuery, start, borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd()); + List params = client.getTableRoute().getTableParams(indexTableName, + tableQuery, start, borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd(), readConsistency); if (tableQuery.getScanOrder() == ObScanOrder.Reverse) { for (int i = params.size() - 1; i >= 0; i--) { @@ -480,8 +471,8 @@ protected Map> buildFirstPartitions(ObTableClie indexTableName = client.tryGetTableNameFromTableGroupCache(tableName, false); } ObBorderFlag borderFlag = range.getBorderFlag(); - List params = this.client.getTableParams(indexTableName, tableQuery, start, - borderFlag.isInclusiveStart(), start, borderFlag.isInclusiveEnd()); + List params = this.client.getTableRoute().getTableParams(indexTableName, tableQuery, start, + borderFlag.isInclusiveStart(), start, borderFlag.isInclusiveEnd(), readConsistency); partitionObTables.put(INVALID_TABLET_ID, new ObPair<>(params.get(0).getPartId(), params.get(0))); } @@ -803,7 +794,7 @@ public void setExpectant(Map> expectant) { /* * Get Read Consistency */ - public ObReadConsistency getReadConsistency() { + public ObTableConsistencyLevel getReadConsistency() { return readConsistency; } @@ -812,7 +803,7 @@ public ObReadConsistency getReadConsistency() { * * @param readConsistency */ - public void setReadConsistency(ObReadConsistency readConsistency) { + public void setReadConsistency(ObTableConsistencyLevel readConsistency) { this.readConsistency = readConsistency; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java index 508adf76..58de58d1 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryAsyncStreamResult.java @@ -57,7 +57,7 @@ public void init() throws Exception { request.setTableName(tableName); request.setTableQuery(tableQuery); request.setEntityType(entityType); - request.setConsistencyLevel(getReadConsistency().toObTableConsistencyLevel()); + request.setConsistencyLevel(getReadConsistency()); request.setHbaseOpType(hbaseOpType); // construct async query request @@ -115,7 +115,8 @@ protected ObTableQueryAsyncResult referToNewPartition(ObPair throws Exception { ObTableParam obTableParam = partIdWithObTable.getRight(); ObTableQueryRequest queryRequest = asyncRequest.getObTableQueryRequest(); - long partitionId = needTabletId(queryRequest) ? obTableParam.getPartitionId() : INVALID_TABLET_ID; + long partitionId = needTabletId(queryRequest) ? obTableParam.getPartitionId() + : INVALID_TABLET_ID; // refresh request info queryRequest.setPartitionId(partitionId); queryRequest.setTableId(obTableParam.getTableId()); @@ -142,7 +143,8 @@ protected ObTableQueryAsyncResult referToLastStreamResult(ObPair partIdWithObTabl ObTableQueryRequest queryRequest = asyncRequest.getObTableQueryRequest(); // refresh request info - long partitionId = needTabletId(queryRequest) ? obTableParam.getPartitionId() : INVALID_TABLET_ID; + long partitionId = needTabletId(queryRequest) ? obTableParam.getPartitionId() + : INVALID_TABLET_ID; queryRequest.setPartitionId(partitionId); queryRequest.setTableId(obTableParam.getTableId()); @@ -179,26 +182,23 @@ protected void closeLastStreamResult(ObPair partIdWithObTabl } public boolean queryLastStreamResultInNext() throws Exception { - Iterator>> it = expectant.entrySet() - .iterator(); + Iterator>> it = expectant.entrySet().iterator(); Map.Entry> lastEntry = it.next(); try { // try access new partition, async will not remove useless expectant referToLastStreamResult(lastEntry.getValue()); } catch (Exception e) { if (shouldRetry(e)) { - String realTableName = client.getPhyTableNameFromTableGroup(entityType, - tableName); + String realTableName = client.getPhyTableNameFromTableGroup(entityType, tableName); TableEntry entry = client.getOrRefreshTableEntry(realTableName, false); // Calculate the next partition only when the range partition is affected by a split, based on the keys already scanned. if (entry.isPartitionTable() - && entry.getPartitionInfo().getLevel() == ObPartitionLevel.LEVEL_ONE - && entry.getPartitionInfo().getFirstPartDesc().getPartFuncType() - .isRangePart()) { + && entry.getPartitionInfo().getLevel() == ObPartitionLevel.LEVEL_ONE + && entry.getPartitionInfo().getFirstPartDesc().getPartFuncType().isRangePart()) { this.asyncRequest.getObTableQueryRequest().getTableQuery() - .adjustStartKey(currentStartKey); - setExpectant(refreshPartition(this.asyncRequest - .getObTableQueryRequest().getTableQuery(), realTableName)); + .adjustStartKey(currentStartKey); + setExpectant(refreshPartition(this.asyncRequest.getObTableQueryRequest() + .getTableQuery(), realTableName)); setEnd(true); } else { // non one-level-range partitioned table does not retry, inform user to rescan @@ -221,8 +221,7 @@ public boolean queryLastStreamResultInNext() throws Exception { public boolean queryNewStreamResultInNext() throws Exception { boolean hasNext = false; - Iterator>> it = expectant.entrySet() - .iterator(); + Iterator>> it = expectant.entrySet().iterator(); int retryTimes = 0; long startExecute = System.currentTimeMillis(); while (it.hasNext()) { @@ -233,17 +232,17 @@ public boolean queryNewStreamResultInNext() throws Exception { } catch (Exception e) { if (shouldRetry(e)) { String realTableName = client.getPhyTableNameFromTableGroup(entityType, - tableName); + tableName); TableEntry tableEntry = client.getOrRefreshTableEntry(realTableName, false); if (tableEntry.isPartitionTable() - && tableEntry.getPartitionInfo().getLevel() == ObPartitionLevel.LEVEL_ONE - && tableEntry.getPartitionInfo().getFirstPartDesc().getPartFuncType() + && tableEntry.getPartitionInfo().getLevel() == ObPartitionLevel.LEVEL_ONE + && tableEntry.getPartitionInfo().getFirstPartDesc().getPartFuncType() .isRangePart()) { this.asyncRequest.getObTableQueryRequest().getTableQuery() - .adjustStartKey(currentStartKey); - setExpectant(refreshPartition(this.asyncRequest - .getObTableQueryRequest().getTableQuery(), realTableName)); - } else { + .adjustStartKey(currentStartKey); + setExpectant(refreshPartition(this.asyncRequest.getObTableQueryRequest() + .getTableQuery(), realTableName)); + } else { // non one-level-range partitioned table does not retry, inform user to rescan throw e; } @@ -252,9 +251,9 @@ public boolean queryNewStreamResultInNext() throws Exception { long costMillis = System.currentTimeMillis() - startExecute; if (costMillis > client.getRuntimeMaxWait()) { RUNTIME.error("Fail to get refresh table entry response after {}", - retryTimes); + retryTimes); throw new ObTableTimeoutExcetion( - "Fail to get refresh table entry response after " + retryTimes); + "Fail to get refresh table entry response after " + retryTimes); } continue; } else { @@ -335,7 +334,7 @@ public boolean next() throws Exception { // new server does not store the current session_id // only support range-partitioned table, check in server this.asyncRequest.getObTableQueryRequest().getTableQuery() - .adjustStartKey(currentStartKey); + .adjustStartKey(currentStartKey); // just need to asjust startKey to anchor the correct position // no need to refresh partition id for session_id missing hasNext = queryNewStreamResultInNext(); diff --git a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java index 3dce44c2..55387db5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/stream/ObTableClientQueryStreamResult.java @@ -46,7 +46,8 @@ protected ObTableQueryResult referToNewPartition(ObPair part ObTableQueryRequest request = new ObTableQueryRequest(); request.setTableName(tableName); request.setTableQuery(tableQuery); - long partitionId = needTabletId(request) ? partIdWithObTable.getRight().getPartitionId() : INVALID_TABLET_ID; + long partitionId = needTabletId(request) ? partIdWithObTable.getRight().getPartitionId() + : INVALID_TABLET_ID; request.setPartitionId(partitionId); request.setTableId(partIdWithObTable.getRight().getTableId()); request.setEntityType(entityType); @@ -57,7 +58,7 @@ protected ObTableQueryResult referToNewPartition(ObPair part request.setTimeout(partIdWithObTable.getRight().getObTable() .getObTableOperationTimeout()); } - request.setConsistencyLevel(getReadConsistency().toObTableConsistencyLevel()); + request.setConsistencyLevel(getReadConsistency()); return execute(partIdWithObTable, request); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableBatchOps.java b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableBatchOps.java index 14aa75d1..08ec9282 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableBatchOps.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableBatchOps.java @@ -28,6 +28,7 @@ public abstract class AbstractTableBatchOps implements TableBatchOps { protected boolean returnOneResult; protected ObTableEntityType entityType = ObTableEntityType.KV; + protected boolean isWeakRead = false; /** * Get. @@ -160,4 +161,20 @@ public void setEntityType(ObTableEntityType entityType) { public ObTableEntityType getEntityType() { return entityType; } + + /* + * Set is weak read. + */ + @Override + public void setIsWeakRead(boolean isWeakRead) { + this.isWeakRead = isWeakRead; + } + + /* + * Is weak read. + */ + @Override + public boolean isWeakRead() { + return isWeakRead; + } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java index b3ea368f..99f94156 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java @@ -26,11 +26,23 @@ import java.util.List; public abstract class AbstractTableQuery implements TableQuery { - private static final String PRIMARY_INDEX_NAME = "PRIMARY"; + private static final String PRIMARY_INDEX_NAME = "PRIMARY"; - protected ObTableEntityType entityType = ObTableEntityType.KV; + protected ObTableEntityType entityType = ObTableEntityType.KV; - protected long operationTimeout = -1; + protected long operationTimeout = -1; + protected String readConsistency = ""; // 空串表示用户没有设置,将使用 TableRoute 上的 consistencyLevel + + @Override + public TableQuery setReadConsistency(String readConsistency) { + this.readConsistency = readConsistency; + return this; + } + + @Override + public String getReadConsistency() { + return readConsistency; + } /* * Limit. diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQueryImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQueryImpl.java index 72d9e39c..ca1a6fa0 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQueryImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQueryImpl.java @@ -23,7 +23,6 @@ import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObNewRange; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObScanOrder; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQuery; -import com.alipay.oceanbase.rpc.table.api.Table; import com.alipay.oceanbase.rpc.table.api.TableQuery; import java.util.Arrays; diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java index ac6c0025..457dd020 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java @@ -20,7 +20,6 @@ import com.alipay.oceanbase.rpc.ObTableClient; import com.alipay.oceanbase.rpc.bolt.transport.TransportCodes; import com.alipay.oceanbase.rpc.exception.*; -import com.alipay.oceanbase.rpc.location.model.ObServerRoute; import com.alipay.oceanbase.rpc.location.model.TableEntry; import com.alipay.oceanbase.rpc.location.model.partition.ObPair; import com.alipay.oceanbase.rpc.mutation.Row; @@ -222,17 +221,6 @@ public List executeWithResult() throws Exception { return results; } - // Helper method to calculate RowKey from ObTableOperation - private Object[] calculateRowKey(ObTableOperation operation) { - ObRowKey rowKeyObject = operation.getEntity().getRowKey(); - int rowKeySize = rowKeyObject.getObjs().size(); - Object[] rowKey = new Object[rowKeySize]; - for (int j = 0; j < rowKeySize; j++) { - rowKey[j] = rowKeyObject.getObj(j).getValue(); - } - return rowKey; - } - public Map>>> prepareOperations(List> operations) throws Exception { Map>>> partitionOperationsMap = new HashMap<>(); @@ -256,8 +244,7 @@ public Map>>> rowKey[j] = rowKeyObject.getObj(j).getValue(); } Row row = obTableClient.transformToRow(tableName, rowKey); - ObTableParam tableParam = obTableClient.getTableParamWithRoute( - tableName, row, obTableClient.getRoute(batchOperation.isReadOnly())); + ObTableParam tableParam = obTableClient.getTableRoute().getTableParam(tableName, row); ObPair>> obTableOperations = partitionOperationsMap .computeIfAbsent(tableParam.getPartId(), k -> new ObPair<>( tableParam, new ArrayList<>())); @@ -308,8 +295,12 @@ public void partitionExecute(ObTableOperationResult[] results, subRequest.setEntityType(entityType); subRequest.setTimeout(subObTable.getObTableOperationTimeout()); if (batchOperation.isReadOnly()) { - subRequest.setConsistencyLevel(obTableClient.getReadConsistency() - .toObTableConsistencyLevel()); + // 如果设置了 isWeakRead,使用弱读;否则使用全局的 readConsistency + if (isWeakRead) { + subRequest.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + } else { + subRequest.setConsistencyLevel(ObTableConsistencyLevel.STRONG); + } } subRequest.setBatchOperationAsAtomic(isAtomicOperation()); subRequest.setBatchOpReturnOneResult(isReturnOneResult()); @@ -319,7 +310,6 @@ public void partitionExecute(ObTableOperationResult[] results, boolean needRefreshPartitionLocation = false; long startExecute = System.currentTimeMillis(); Set failedServerList = null; - ObServerRoute route = null; while (true) { obTableClient.checkStatus(); @@ -344,20 +334,15 @@ public void partitionExecute(ObTableOperationResult[] results, // getTable() when we need retry // we should use partIdx to get table if (tryTimes > 1) { - if (route == null) { - route = obTableClient.getRoute(batchOperation.isReadOnly()); - } - if (failedServerList != null) { - route.setBlackList(failedServerList); - } if (needRefreshPartitionLocation) { // refresh partition location TableEntry entry = obTableClient.getOrRefreshTableEntry(tableName, false); obTableClient.refreshTableLocationByTabletId(tableName, obTableClient.getTabletIdByPartId(entry, originPartId)); - ObTableParam newParam = obTableClient.getTableParamWithPartId( - tableName, originPartId, route); + ObTableParam newParam = obTableClient.getTableRoute() + .getTableWithPartId(tableName, originPartId, + ObTableConsistencyLevel.STRONG); subObTable = newParam.getObTable(); subRequest.setPartitionId(newParam.getPartitionId()); } @@ -379,11 +364,14 @@ public void partitionExecute(ObTableOperationResult[] results, throw new ObTableRoutingWrongException(); } } else if (result != null && result.isRoutingWrong() && !obTableClient.isOdpMode()) { - logger.debug("errors happened in server and retried successfully, server ip:port is {}:{}, tableName: {}, need_refresh_meta: {}", - subObTable.getIp(), subObTable.getPort(), tableName, result.isNeedRefreshMeta()); - TableEntry entry = result.isNeedRefreshMeta() ? - obTableClient.getOrRefreshTableEntry(tableName, true) : - obTableClient.getOrRefreshTableEntry(tableName, false); + logger + .debug( + "errors happened in server and retried successfully, server ip:port is {}:{}, tableName: {}, need_refresh_meta: {}", + subObTable.getIp(), subObTable.getPort(), tableName, + result.isNeedRefreshMeta()); + TableEntry entry = result.isNeedRefreshMeta() ? obTableClient + .getOrRefreshTableEntry(tableName, true) : obTableClient + .getOrRefreshTableEntry(tableName, false); long tabletId = obTableClient.getTabletIdByPartId(entry, originPartId); obTableClient.refreshTableLocationByTabletId(tableName, tabletId); } @@ -425,10 +413,14 @@ public void partitionExecute(ObTableOperationResult[] results, if (obTableClient.isRetryOnChangeMasterTimes()) { if (ex instanceof ObTableNeedFetchMetaException) { // refresh table info - TableEntry entry = obTableClient.getOrRefreshTableEntry(tableName, true); - if (((ObTableNeedFetchMetaException) ex).isNeedRefreshMetaAndLocation()) { - long tabletId = obTableClient.getTabletIdByPartId(entry, originPartId); - obTableClient.refreshTableLocationByTabletId(tableName, tabletId); + TableEntry entry = obTableClient.getOrRefreshTableEntry(tableName, + true); + if (((ObTableNeedFetchMetaException) ex) + .isNeedRefreshMetaAndLocation()) { + long tabletId = obTableClient.getTabletIdByPartId(entry, + originPartId); + obTableClient.refreshTableLocationByTabletId(tableName, + tabletId); } throw ex; } @@ -462,10 +454,12 @@ public void partitionExecute(ObTableOperationResult[] results, } else { if (ex instanceof ObTableTransportException && ((ObTableTransportException) ex).getErrorCode() == TransportCodes.BOLT_TIMEOUT) { - logger.debug("normal batch meet transport timeout, obTable ip:port is {}:{}", - subObTable.getIp(), subObTable.getPort()); + logger.debug( + "normal batch meet transport timeout, obTable ip:port is {}:{}", + subObTable.getIp(), subObTable.getPort()); subObTable.setDirty(); - obTableClient.dealWithRpcTimeoutForSingleTablet(subObTable.getObServerAddr(), tableName, partId); + obTableClient.dealWithRpcTimeoutForSingleTablet( + subObTable.getObServerAddr(), tableName, partId); } obTableClient.calculateContinuousFailure(tableName, ex.getMessage()); throw ex; diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java index 08b4c34d..5915e1ad 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java @@ -23,7 +23,6 @@ import com.alipay.oceanbase.rpc.exception.*; import com.alipay.oceanbase.rpc.get.Get; import com.alipay.oceanbase.rpc.get.result.GetResult; -import com.alipay.oceanbase.rpc.location.model.ObServerRoute; import com.alipay.oceanbase.rpc.location.model.TableEntry; import com.alipay.oceanbase.rpc.location.model.partition.ObPair; import com.alipay.oceanbase.rpc.mutation.*; @@ -380,6 +379,9 @@ public List execute() throws Exception { public List executeWithResult() throws Exception { List results = new ArrayList(batchOperation.size()); ObTableSingleOpResult[] singleResults = executeInternal(); + if (singleResults.length == 1 && singleResults[0] == null) { // get empty result + return results; + } for (int i = 0; i < singleResults.length; i++) { ObTableSingleOpResult result = singleResults[i]; // Sometimes the server does not set the operation type,so we use request operation type @@ -446,6 +448,8 @@ public LsOperationsMap prepareOperations(BatchIdxOperationPairList operationsWit private LsOperationsMap prepareByFirstOperation(LsOperationsMap lsOperationsMap, BatchIdxOperationPairList operationsWithIndex) throws Exception { + + ObTableConsistencyLevel consistencyLevel = isWeakRead ? ObTableConsistencyLevel.EVENTUAL : ObTableConsistencyLevel.STRONG; if (operationsWithIndex.isEmpty()) { throw new IllegalArgumentException("batch operations is empty"); } else { @@ -458,7 +462,7 @@ private LsOperationsMap prepareByFirstOperation(LsOperationsMap lsOperationsMap, } ObTableParam obTableParam = null; try { - obTableParam = obTableClient.getTableParamWithRoute(realTableName, rowKey, obTableClient.getRoute(false)); + obTableParam = obTableClient.getTableRoute().getTableParam(realTableName, rowKey, consistencyLevel); } catch (ObTableNotExistException e) { logger.warn("LSBatch meet TableNotExist Exception, realTableName: {}, errMsg: {}", realTableName, e.getMessage()); // if it is HKV and is tableGroup request, TableNotExist and tableGroup cache not empty mean that the table cached had been dropped @@ -468,7 +472,7 @@ private LsOperationsMap prepareByFirstOperation(LsOperationsMap lsOperationsMap, && obTableClient.getTableGroupInverted().get(realTableName) != null) { obTableClient.eraseTableGroupFromCache(tableName); realTableName = obTableClient.tryGetTableNameFromTableGroupCache(tableName, true); - obTableParam = obTableClient.getTableParamWithRoute(realTableName, rowKey, obTableClient.getRoute(false)); + obTableParam = obTableClient.getTableRoute().getTableParam(realTableName, rowKey, consistencyLevel); } else { throw e; } @@ -486,6 +490,7 @@ private LsOperationsMap prepareByFirstOperation(LsOperationsMap lsOperationsMap, private LsOperationsMap prepareByEachOperation(LsOperationsMap lsOperationsMap, BatchIdxOperationPairList operationsWithIndex) throws Exception { + ObTableConsistencyLevel consistencyLevel = isWeakRead ? ObTableConsistencyLevel.EVENTUAL : ObTableConsistencyLevel.STRONG; for (int i = 0; i < operationsWithIndex.size(); i++) { ObPair operation = operationsWithIndex.get(i); Row rowKey = calculateRowKey(operation); @@ -496,7 +501,7 @@ private LsOperationsMap prepareByEachOperation(LsOperationsMap lsOperationsMap, } ObTableParam tableParam = null; try { - tableParam = obTableClient.getTableParamWithRoute(realTableName, rowKey, obTableClient.getRoute(false)); + tableParam = obTableClient.getTableRoute().getTableParam(realTableName, rowKey, consistencyLevel); } catch (ObTableNotExistException e) { logger.warn("LSBatch meet TableNotExist Exception, realTableName: {}, errMsg: {}", realTableName, e.getMessage()); // if it is HKV and is tableGroup request, TableNotExist and tableGroup cache not empty mean that the table cached had been dropped @@ -506,7 +511,7 @@ private LsOperationsMap prepareByEachOperation(LsOperationsMap lsOperationsMap, && obTableClient.getTableGroupInverted().get(realTableName) != null) { obTableClient.eraseTableGroupFromCache(tableName); realTableName = obTableClient.tryGetTableNameFromTableGroupCache(tableName, true); - tableParam = obTableClient.getTableParamWithRoute(realTableName, rowKey, obTableClient.getRoute(false)); + tableParam = obTableClient.getTableRoute().getTableParam(realTableName, rowKey, consistencyLevel); } else { throw e; } @@ -596,13 +601,17 @@ public void partitionExecute(ObTableSingleOpResult[] results, tableLsOpRequest.setTableId(tableId); tableLsOpRequest.setEntityType(entityType); tableLsOpRequest.setTimeout(operationTimeout); + if (isWeakRead) { + tableLsOpRequest.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + } else { + tableLsOpRequest.setConsistencyLevel(ObTableConsistencyLevel.STRONG); + } tableLsOpRequest.setHbaseOpType(hbaseOpType); ObTableLSOpResult subLSOpResult; boolean needRefreshPartitionLocation = false; int tryTimes = 0; Set failedServerList = null; - ObServerRoute route = null; // maybe get real table name String realTableName = obTableClient.getPhyTableNameFromTableGroup(tableLsOpRequest.getEntityType(), tableName); long startExecute = System.currentTimeMillis(); @@ -625,17 +634,12 @@ public void partitionExecute(ObTableSingleOpResult[] results, subObTable = obTableClient.getOdpTable(); } else { if (tryTimes > 1) { - if (route == null) { - route = obTableClient.getRoute(false); - } - if (failedServerList != null) { - route.setBlackList(failedServerList); - } if (needRefreshPartitionLocation) { // refresh partition location + ObTableConsistencyLevel consistencyLevel = isWeakRead ? ObTableConsistencyLevel.EVENTUAL : ObTableConsistencyLevel.STRONG; TableEntry entry = obTableClient.getOrRefreshTableEntry(realTableName, false); obTableClient.refreshTableLocationByTabletId(realTableName, obTableClient.getTabletIdByPartId(entry, originPartId)); - ObTableParam param = obTableClient.getTableParamWithPartId(realTableName, originPartId, route); + ObTableParam param = obTableClient.getTableRoute().getTableWithPartId(realTableName, originPartId, consistencyLevel); subObTable = param.getObTable(); } } @@ -855,9 +859,9 @@ private void executeWithRetries(ObTableSingleOpResult[] results, long costMillis = System.currentTimeMillis() - startExecute; if (costMillis > runTimeMaxWait) { errMsg = tableName + " failed to execute operation after retrying " + retryCount - + " times and it has waited " + costMillis + " ms" - + " which exceeds runtime max wait timeout " + runTimeMaxWait - + " ms. Last error Msg:" + "[errCode=" + errCode + "] " + errMsg; + + " times and it has waited " + costMillis + " ms" + + " which exceeds runtime max wait timeout " + runTimeMaxWait + + " ms. Last error Msg:" + "[errCode=" + errCode + "] " + errMsg; logger.error(errMsg); throw new ObTableUnexpectedException(errMsg); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java index 50baca59..e931300b 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java @@ -22,12 +22,12 @@ import com.alipay.oceanbase.rpc.exception.FeatureNotSupportedException; import com.alipay.oceanbase.rpc.exception.ObTableException; import com.alipay.oceanbase.rpc.exception.ObTableNotExistException; -import com.alipay.oceanbase.rpc.location.model.ObServerRoute; import com.alipay.oceanbase.rpc.location.model.partition.ObPair; import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.protocol.payload.ObPayload; import com.alipay.oceanbase.rpc.protocol.payload.ResultCodes; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObRowKey; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.OHOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.aggregation.ObTableAggregationType; @@ -43,7 +43,6 @@ import java.util.Map; import static com.alipay.oceanbase.rpc.protocol.payload.Constants.INVALID_TABLET_ID; -import static com.alipay.oceanbase.rpc.protocol.payload.Constants.OB_INVALID_ID; public class ObTableClientQueryImpl extends AbstractTableQueryImpl { @@ -156,19 +155,19 @@ public void checkArgumentBeforeExec() throws Exception { /* * Set parameter into request */ - private void setCommonParams2Result(AbstractQueryStreamResult result) throws Exception { + private void setCommonParams2Result(AbstractQueryStreamResult result, ObTableConsistencyLevel actualReadConsistency) throws Exception { result.setTableQuery(tableQuery); result.setEntityType(entityType); result.setTableName(tableName); result.setIndexTableName(indexTableName); result.setExpectant(partitionObTables); result.setOperationTimeout(operationTimeout); - result.setReadConsistency(obTableClient.getReadConsistency()); + result.setReadConsistency(actualReadConsistency); result.setHbaseOpType(hbaseOpType); } private abstract static class InitQueryResultCallback { - abstract T execute() throws Exception; + abstract T execute(ObTableConsistencyLevel actualReadConsistency) throws Exception; } private AbstractQueryStreamResult commonExecute(InitQueryResultCallback callable) @@ -178,6 +177,14 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback>(); // partitionObTables -> Map> + // 如果没有设置语句级别的 readConsistency(空串或null),使用 TableRoute 上的 consistencyLevel + ObTableConsistencyLevel actualReadConsistency; + if (readConsistency == null || readConsistency.isEmpty()) { + actualReadConsistency = obTableClient.getTableRoute().getReadConsistency(); + } else { + actualReadConsistency = ObTableConsistencyLevel.getByName(readConsistency); + } + // fill a whole range if no range is added explicitly. if (tableQuery.getKeyRanges().isEmpty()) { tableQuery.addKeyRange(ObNewRange.getWholeRange()); @@ -197,7 +204,7 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback(odpTable.getPartId(), odpTable)); } catch (Exception e) { if (e instanceof ObTableException) { @@ -208,7 +215,7 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback(odpTable.getPartId(), odpTable)); } else { throw e; @@ -223,7 +230,7 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback(table.getPartId(), table)); } catch (ObTableNotExistException e) { if (this.entityType == ObTableEntityType.HKV @@ -244,8 +251,8 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback(table.getPartId(), table)); } } @@ -270,7 +277,7 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback() { @Override - ObTableClientQueryStreamResult execute() throws Exception { + ObTableClientQueryStreamResult execute(ObTableConsistencyLevel actualReadConsistency) throws Exception { ObTableClientQueryStreamResult obTableClientQueryStreamResult = new ObTableClientQueryStreamResult(); - setCommonParams2Result(obTableClientQueryStreamResult); + setCommonParams2Result(obTableClientQueryStreamResult, actualReadConsistency); obTableClientQueryStreamResult.setClient(obTableClient); obTableClientQueryStreamResult.init(); return obTableClientQueryStreamResult; @@ -300,10 +307,10 @@ ObTableClientQueryStreamResult execute() throws Exception { public ObTableClientQueryAsyncStreamResult asyncExecuteInternal() throws Exception { return (ObTableClientQueryAsyncStreamResult) commonExecute(new InitQueryResultCallback() { @Override - ObTableClientQueryAsyncStreamResult execute() throws Exception { + ObTableClientQueryAsyncStreamResult execute(ObTableConsistencyLevel actualReadConsistency) throws Exception { ObTableClientQueryAsyncStreamResult obTableClientQueryAsyncStreamResult = new ObTableClientQueryAsyncStreamResult(); obTableClientQueryAsyncStreamResult.setAllowDistributeScan(allowDistributeScan); - setCommonParams2Result(obTableClientQueryAsyncStreamResult); + setCommonParams2Result(obTableClientQueryAsyncStreamResult, actualReadConsistency); obTableClientQueryAsyncStreamResult.setClient(obTableClient); obTableClientQueryAsyncStreamResult.init(); return obTableClientQueryAsyncStreamResult; @@ -311,7 +318,7 @@ ObTableClientQueryAsyncStreamResult execute() throws Exception { }); } - public Map> initFirstPartition(ObTableQuery tableQuery, String tableName) throws Exception { + public Map> initFirstPartition(ObTableQuery tableQuery, String tableName, ObTableConsistencyLevel actualReadConsistency) throws Exception { Map> partitionObTables = new LinkedHashMap<>(); String indexName = tableQuery.getIndexName(); @@ -336,8 +343,8 @@ public Map> initFirstPartition(ObTableQuery tab indexTableName = obTableClient.tryGetTableNameFromTableGroupCache(tableName, false); } ObBorderFlag borderFlag = range.getBorderFlag(); - List params = this.obTableClient.getTableParams(indexTableName, tableQuery, start, - borderFlag.isInclusiveStart(), start, borderFlag.isInclusiveEnd()); + List params = this.obTableClient.getTableRoute().getTableParams(indexTableName, tableQuery, start, + borderFlag.isInclusiveStart(), start, borderFlag.isInclusiveEnd(), actualReadConsistency); partitionObTables.put(INVALID_TABLET_ID, new ObPair<>(params.get(0).getPartId(), params.get(0))); } @@ -345,7 +352,7 @@ public Map> initFirstPartition(ObTableQuery tab return partitionObTables; } - public Map> initPartitions(ObTableQuery tableQuery, String tableName) throws Exception { + public Map> initPartitions(ObTableQuery tableQuery, String tableName, ObTableConsistencyLevel actualReadConsistency) throws Exception { // partitionObTables -> > Map> partitionObTables = new LinkedHashMap<>(); String indexName = tableQuery.getIndexName(); @@ -375,8 +382,8 @@ public Map> initPartitions(ObTableQuery tableQu indexTableName = obTableClient.tryGetTableNameFromTableGroupCache(tableName, false); } ObBorderFlag borderFlag = range.getBorderFlag(); - List params = this.obTableClient.getTableParams(indexTableName, tableQuery, start, - borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd()); + List params = this.obTableClient.getTableRoute().getTableParams(indexTableName, tableQuery, start, + borderFlag.isInclusiveStart(), end, borderFlag.isInclusiveEnd(), actualReadConsistency); if (tableQuery.getScanOrder() == ObScanOrder.Reverse) { for (int i = params.size() - 1; i >= 0; i--) { ObTableParam param = params.get(i); @@ -395,11 +402,11 @@ public Map> initPartitions(ObTableQuery tableQu /* * Init partition tables involved in this query */ - public void initPartitions() throws Exception { + public void initPartitions(ObTableConsistencyLevel actualReadConsistency) throws Exception { if (obTableClient.getServerCapacity().isSupportDistributedExecute()) { - this.partitionObTables = initFirstPartition(tableQuery, tableName); + this.partitionObTables = initFirstPartition(tableQuery, tableName, actualReadConsistency); } else { - this.partitionObTables = initPartitions(tableQuery, tableName); + this.partitionObTables = initPartitions(tableQuery, tableName, actualReadConsistency); } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/api/TableBatchOps.java b/src/main/java/com/alipay/oceanbase/rpc/table/api/TableBatchOps.java index 631aa8f9..b9f0b874 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/api/TableBatchOps.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/api/TableBatchOps.java @@ -40,6 +40,10 @@ public interface TableBatchOps { ObTableEntityType getEntityType(); + void setIsWeakRead(boolean isWeakRead); + + boolean isWeakRead(); + void get(Object rowkey, String[] columns); void get(Object[] rowkeys, String[] columns); diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java index a928a879..c59ac536 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java @@ -18,14 +18,11 @@ package com.alipay.oceanbase.rpc.table.api; import com.alipay.oceanbase.rpc.filter.ObTableFilter; -import com.alipay.oceanbase.rpc.location.model.partition.ObPair; import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObHTableFilter; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQuery; import com.alipay.oceanbase.rpc.stream.QueryResultSet; -import com.alipay.oceanbase.rpc.table.ObTable; -import com.alipay.oceanbase.rpc.table.ObTableParam; import java.util.List; @@ -201,4 +198,8 @@ public interface TableQuery { void clear(); TableQuery setSearchText(String searchText); + + TableQuery setReadConsistency(String readConsistency); + + String getReadConsistency(); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/threadlocal/ThreadLocalMap.java b/src/main/java/com/alipay/oceanbase/rpc/threadlocal/ThreadLocalMap.java index fc996751..f9383184 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/threadlocal/ThreadLocalMap.java +++ b/src/main/java/com/alipay/oceanbase/rpc/threadlocal/ThreadLocalMap.java @@ -17,7 +17,6 @@ package com.alipay.oceanbase.rpc.threadlocal; -import com.alipay.oceanbase.rpc.location.model.ObReadConsistency; import com.alipay.oceanbase.rpc.util.TableClientLoggerFactory; import org.slf4j.Logger; @@ -67,20 +66,6 @@ public static short getProcessPriority() { return (Short) getContextMap().get(PROCESS_PRIORITY); } - /* - * Set read consistency. - */ - public static void setReadConsistency(ObReadConsistency readConsistency) { - getContextMap().put(READ_CONSISTENCY, readConsistency); - } - - /* - * Get read consistency. - */ - public static ObReadConsistency getReadConsistency() { - return (ObReadConsistency) getContextMap().get(READ_CONSISTENCY); - } - /* * Clear read consistency. */ diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableClientAutoIncTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableClientAutoIncTest.java index 14162178..013cccfc 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/ObTableClientAutoIncTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableClientAutoIncTest.java @@ -18,7 +18,6 @@ package com.alipay.oceanbase.rpc; import com.alipay.oceanbase.rpc.bolt.ObTableClientTestBase; -import com.alipay.oceanbase.rpc.bolt.ObTableTest; import com.alipay.oceanbase.rpc.exception.ObTableException; import com.alipay.oceanbase.rpc.filter.ObCompareOp; import com.alipay.oceanbase.rpc.filter.ObTableValueFilter; diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableClientCheckAndInsertTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableClientCheckAndInsertTest.java index 66885bf6..a7e5a60f 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/ObTableClientCheckAndInsertTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableClientCheckAndInsertTest.java @@ -18,7 +18,6 @@ package com.alipay.oceanbase.rpc; import com.alipay.oceanbase.rpc.bolt.ObTableClientTestBase; -import com.alipay.oceanbase.rpc.bolt.ObTableTest; import com.alipay.oceanbase.rpc.exception.ObTableUnexpectedException; import com.alipay.oceanbase.rpc.filter.ObCompareOp; import com.alipay.oceanbase.rpc.filter.ObTableValueFilter; diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java new file mode 100644 index 00000000..88ef462f --- /dev/null +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java @@ -0,0 +1,2141 @@ +/*- + * #%L + * com.oceanbase:obkv-table-client + * %% + * Copyright (C) 2021 - 2025 OceanBase + * %% + * OBKV Table Client Framework is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + * #L% + */ + +package com.alipay.oceanbase.rpc; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import com.alipay.oceanbase.rpc.exception.ObTableException; +import com.alipay.oceanbase.rpc.get.Get; +import com.alipay.oceanbase.rpc.mutation.BatchOperation; +import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; +import com.alipay.oceanbase.rpc.stream.QueryResultSet; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static com.alipay.oceanbase.rpc.mutation.MutationFactory.colVal; +import static com.alipay.oceanbase.rpc.mutation.MutationFactory.row; + +class SqlAuditResult { + public String svrIp; + public int svrPort; + public int tabletId; + + public SqlAuditResult(String svrIp, int svrPort, int tabletId) { + this.svrIp = svrIp; + this.svrPort = svrPort; + this.tabletId = tabletId; + } + + @Override + public String toString() { + return "SqlAuditResult{" + "svrIp='" + svrIp + '\'' + ", svrPort=" + svrPort + ", tabletId=" + tabletId + '}'; + } +} + +class ReplicaLocation { + public String zone; + public String region; + public String idc; + public String svrIp; + public int svrPort; + public String role; + + public ReplicaLocation(String zone, String region, String idc, String svrIp, int svrPort, String role) { + this.zone = zone; + this.region = region; + this.idc = idc; + this.svrIp = svrIp; + this.svrPort = svrPort; + this.role = role; + } + + public boolean isLeader() { + return role.equalsIgnoreCase("LEADER"); + } + + public boolean isFollower() { + return role.equalsIgnoreCase("FOLLOWER"); + } + + public String getZone() { + return zone; + } + + public String getRegion() { + return region; + } + + public String getIdc() { + return idc; + } + + public String getSvrIp() { + return svrIp; + } + + public int getSvrPort() { + return svrPort; + } + + public String getRole() { + return role; + } + public String toString() { + return "ReplicaLocation{" + "zone=" + zone + ", region=" + region + ", idc=" + idc + ", svrIp=" + svrIp + ", svrPort=" + svrPort + ", role=" + role + '}'; + } +} + +class PartitionLocation { + ReplicaLocation leader; + List replicas; + + public PartitionLocation(ReplicaLocation leader, List replicas) { + this.leader = leader; + this.replicas = replicas; + } + + public ReplicaLocation getLeader() { + return leader; + } + + public List getReplicas() { + return replicas; + } + + public ReplicaLocation getReplicaBySvrAddr(String svrIp, int svrPort) throws Exception { + if (leader.svrIp.equals(svrIp) && leader.svrPort == svrPort) { + return leader; + } + for (ReplicaLocation replica : replicas) { + if (replica.svrIp.equals(svrIp) && replica.svrPort == svrPort) { + return replica; + } + } + throw new Exception("Failed to get replica from partition location for svrIp: " + svrIp + " and svrPort: " + svrPort); + } + + public String toString() { + return "PartitionLocation{" + "leader=" + leader + ", replicas=" + replicas + '}'; + } +} + +/* +CREATE TABLE IF NOT EXISTS `test_weak_read` ( + `c1` varchar(20) NOT NULL, + `c2` varchar(20) default NULL, + PRIMARY KEY (`c1`) + ) PARTITION BY KEY(`c1`) PARTITIONS 97; + */ +public class ObTableWeakReadTest { + // 测试配置常量 + private static String FULL_USER_NAME = ""; + private static String PARAM_URL = ""; + private static String PASSWORD = ""; + private static String PROXY_SYS_USER_NAME = "root"; + private static String PROXY_SYS_USER_PASSWORD = ""; + private static boolean USE_ODP = false; + private static String ODP_IP = "ip-addr"; + private static int ODP_PORT = 0; + private static String ODP_DATABASE = "database-name"; + private static String JDBC_IP = ""; + private static String JDBC_PORT = ""; + private static String JDBC_URL = "jdbc:mysql://"+JDBC_IP+":"+JDBC_PORT+"/test?rewriteBatchedStatements=TRUE&allowMultiQueries=TRUE&useLocalSessionState=TRUE&useUnicode=TRUE&characterEncoding=utf-8&socketTimeout=30000000&connectTimeout=600000&sessionVariables=ob_query_timeout=60000000000"; + + private static boolean printDebug = true; + private static int SQL_AUDIT_PERSENT = 20; + private static String TENANT_NAME = "mysql"; + private static String TABLE_NAME = "test_weak_read"; + private int tenant_id = 0; + private static String ZONE1 = "zone1"; + private static String ZONE2 = "zone2"; + private static String ZONE3 = "zone3"; + private static String IDC1 = "idc1"; + private static String IDC2 = "idc2"; + private static String IDC3 = "idc3"; + private static String GET_STMT_TYPE = "KV_GET"; + private static String SCAN_STMT_TYPE = "KV_QUERY"; + private static String BATCH_GET_STMT_TYPE = "KV_MULTI_GET"; + private static String INSERT_STMT_TYPE = "KV_INSERT"; + private static String UPDATE_STMT_TYPE = "KV_UPDATE"; + private static String DELETE_STMT_TYPE = "KV_DELETE"; + private static String REPLACE_STMT_TYPE = "KV_REPLACE"; + private static String INSERT_OR_UPDATE_STMT_TYPE = "KV_INSERT_OR_UPDATE"; + private static String PUT_STMT_TYPE = "KV_PUT"; + private static String INCREMENT_STMT_TYPE = "KV_INCREMENT"; + private static String APPEND_STMT_TYPE = "KV_APPEND"; + private static String CREATE_TABLE_SQL = "CREATE TABLE IF NOT EXISTS `test_weak_read` ( " + + " `c1` varchar(20) NOT NULL, " + + " `c2` varchar(20) default NULL, " + + " PRIMARY KEY (`c1`) " + + " ) PARTITION BY KEY(`c1`) PARTITIONS 97;"; + private static String SQL_AUDIT_SQL = "select svr_ip, svr_port, query_sql from oceanbase.GV$OB_SQL_AUDIT " + + "where query_sql like ? and tenant_id = ? and stmt_type = ? limit 1;"; + private static String PARTITION_LOCATION_SQL = "SELECT t.zone, t.svr_ip, t.svr_port, t.role, z.idc, z.region " + + "FROM oceanbase.CDB_OB_TABLE_LOCATIONS t JOIN oceanbase.DBA_OB_ZONES z ON t.zone = z.zone " + + "WHERE t.table_name = ? AND t.tenant_id = ? AND t.tablet_id = ?;"; + private static String SET_SQL_AUDIT_PERSENT_SQL = "SET GLOBAL ob_sql_audit_percentage =?;"; + private static String GET_TENANT_ID_SQL = "SELECT tenant_id FROM oceanbase.__all_tenant WHERE tenant_name = ?"; + private Connection tenantConnection = null; + private Connection sysConnection = null; + private static Connection staticTenantConnection = null; + private static Connection staticSysConnection = null; + private static int staticTenantId = 0; + private static boolean clear = false; + + /** + * 创建新的测试客户端 + */ + private static ObTableClient newTestClient() throws Exception { + ObTableClient obTableClient = new ObTableClient(); + if (!USE_ODP) { + obTableClient.setFullUserName(FULL_USER_NAME); + obTableClient.setParamURL(PARAM_URL); + obTableClient.setPassword(PASSWORD); + obTableClient.setSysUserName(PROXY_SYS_USER_NAME); + obTableClient.setSysPassword(PROXY_SYS_USER_PASSWORD); + } else { + obTableClient.setOdpMode(true); + obTableClient.setFullUserName(FULL_USER_NAME); + obTableClient.setOdpAddr(ODP_IP); + obTableClient.setOdpPort(ODP_PORT); + obTableClient.setDatabase(ODP_DATABASE); + obTableClient.setPassword(PASSWORD); + } + return obTableClient; + } + + /** + * 获取租户连接 + */ + private static Connection getConnection() throws SQLException { + String[] userNames = FULL_USER_NAME.split("#"); + return DriverManager.getConnection(JDBC_URL, userNames[0], PASSWORD); + } + + /** + * 获取系统连接 + */ + private static Connection getSysConnection() throws SQLException { + return DriverManager.getConnection(JDBC_URL, "root@sys", PASSWORD); + } + + @org.junit.BeforeClass + public static void beforeClass() throws Exception { + // 所有测试用例执行前创建表和连接(只执行一次) + staticTenantConnection = getConnection(); + staticSysConnection = getSysConnection(); + staticTenantId = getTenantId(staticSysConnection); + createTable(staticTenantConnection); + setSqlAuditPersent(staticTenantConnection, SQL_AUDIT_PERSENT); + } + + @org.junit.AfterClass + public static void afterClass() throws Exception { + if (clear) { + dropTable(staticTenantConnection); + } + } + + @Before + public void setup() throws Exception { + tenantConnection = staticTenantConnection; + sysConnection = staticSysConnection; + tenant_id = staticTenantId; + } + + @After + public void tearDown() throws Exception { + if (clear) { + cleanupAllData(tenantConnection); + } + } + + /** + * 使用SQL清理所有测试数据 + * @param connection 数据库连接 + */ + private static void cleanupAllData(Connection connection) throws Exception { + try { + PreparedStatement statement = connection.prepareStatement("DELETE FROM " + TABLE_NAME); + int deletedRows = statement.executeUpdate(); + if (printDebug) { + System.out.println("[DEBUG] Cleaned up " + deletedRows + " rows from table " + TABLE_NAME); + } + statement.close(); + } catch (Exception e) { + if (printDebug) { + System.out.println("[DEBUG] Failed to cleanup data from table " + TABLE_NAME + ", error: " + e.getMessage()); + } + // 清理失败不影响测试,只打印警告 + } + } + + private static void setMinimalImage(Connection connection) throws Exception { + Statement statement = connection.createStatement(); + statement.execute("SET GLOBAL binlog_row_image=MINIMAL"); + } + + private static void setFullImage(Connection connection) throws Exception { + Statement statement = connection.createStatement(); + statement.execute("SET GLOBAL binlog_row_image=Full"); + } + + private static void createTable(Connection connection) throws Exception { + PreparedStatement statement = connection.prepareStatement(CREATE_TABLE_SQL); + statement.execute(); + statement.close(); + } + + private static void dropTable(Connection connection) throws Exception { + PreparedStatement statement = connection.prepareStatement("DROP TABLE IF EXISTS " + TABLE_NAME); + statement.execute(); + statement.close(); + } + + private void setZoneIdc(String zone, String idc) throws Exception { + PreparedStatement statement = sysConnection.prepareStatement("ALTER SYSTEM MODIFY ZONE ? SET IDC = ?;"); + statement.setString(1, zone); + statement.setString(2, idc); + debugPrint("setZoneIdc SQL: %s", statement.toString()); + statement.execute(); + } + + // 通过当前纳秒时间戳生成随机字符串 + private String getRandomRowkString() { + return System.nanoTime() + ""; + } + + // 从 querySql 中提取 tablet_id + private int extractTabletId(String querySql) { + // 查找 tablet_id:{id: 的模式 + String pattern = "tablet_id:{id:"; + int startIndex = querySql.indexOf(pattern); + if (startIndex == -1) { + return -1; + } + // 找到 id: 后面的数字开始位置 + int idStartIndex = startIndex + pattern.length(); + // 跳过可能的空格 + while (idStartIndex < querySql.length() && Character.isWhitespace(querySql.charAt(idStartIndex))) { + idStartIndex++; + } + // 找到数字结束位置(遇到 } 或 , 或空格) + int idEndIndex = idStartIndex; + while (idEndIndex < querySql.length()) { + char c = querySql.charAt(idEndIndex); + if (c == '}' || c == ',' || c == ' ') { + break; + } + idEndIndex++; + } + // 提取数字字符串 + String tabletIdStr = querySql.substring(idStartIndex, idEndIndex).trim(); + try { + return Integer.parseInt(tabletIdStr); + } catch (NumberFormatException e) { + debugPrint("Failed to parse tablet_id from: %s", tabletIdStr); + return -1; + } + } + + private static int getTenantId(Connection connection) throws Exception { + PreparedStatement statement = connection.prepareStatement(GET_TENANT_ID_SQL); + statement.setString(1, TENANT_NAME); + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + return resultSet.getInt("tenant_id"); + } + throw new ObTableException("Failed to get tenant id for tenant: " + TENANT_NAME); + } + + private static void setSqlAuditPersent(Connection connection, int persent) throws Exception { + PreparedStatement statement = connection.prepareStatement(SET_SQL_AUDIT_PERSENT_SQL); + statement.setInt(1, persent); + statement.execute(); + } + + // 通过SQL审计获取服务器地址,确认rowkey落在哪个服务器上 + private SqlAuditResult getServerBySqlAudit(String rowkey, String stmtType) throws Exception { + SqlAuditResult sqlAuditResult = null; + PreparedStatement statement = tenantConnection.prepareStatement(SQL_AUDIT_SQL); + statement.setString(1, "%" + rowkey + "%"); + statement.setInt(2, this.tenant_id); + statement.setString(3, stmtType); + debugPrint("SQL: %s", statement.toString()); + try { + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + String svrIp = resultSet.getString("svr_ip"); + int svrPort = resultSet.getInt("svr_port"); + String querySql = resultSet.getString("query_sql"); + int tabletId = extractTabletId(querySql); + sqlAuditResult = new SqlAuditResult(svrIp, svrPort, tabletId); + debugPrint("querySql: %s", querySql); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + } + resultSet.close(); + } finally { + statement.close(); + } + + if (sqlAuditResult == null) { + throw new ObTableException("Failed to get server address from sql audit for rowkey: " + + rowkey + " and stmtType: " + stmtType); + } + + return sqlAuditResult; + } + + private PartitionLocation getPartitionLocation(int tabletId) throws Exception { + ReplicaLocation leader = null; + List replicas = new ArrayList<>(); + PreparedStatement statement = sysConnection.prepareStatement(PARTITION_LOCATION_SQL); + statement.setString(1, TABLE_NAME); + statement.setInt(2, this.tenant_id); // 使用成员变量 tenant_id + statement.setInt(3, tabletId); + debugPrint("PARTITION_LOCATION_SQL: %s", statement.toString()); + ResultSet resultSet = statement.executeQuery(); + while (resultSet.next()) { + String zone = resultSet.getString("zone"); + String region = resultSet.getString("region"); + String idc = resultSet.getString("idc"); + String svrIp = resultSet.getString("svr_ip"); + int svrPort = resultSet.getInt("svr_port"); + String role = resultSet.getString("role"); + if (role.equalsIgnoreCase("LEADER")) { + leader = new ReplicaLocation(zone, region, idc, svrIp, svrPort, role); + } else { + replicas.add(new ReplicaLocation(zone, region, idc, svrIp, svrPort, role)); + } + } + if (leader == null) { + throw new ObTableException("Failed to get leader from partition location for tabletId: " + tabletId); + } + return new PartitionLocation(leader, replicas); + } + + private void insertData(ObTableClient client, String rowkey) throws Exception { + client.insertOrUpdate(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "c2_val"))).execute(); + } + + + /** + * 封装debug打印方法 + * @param message 要打印的消息 + */ + private void debugPrint(String message) { + if (printDebug) { + System.out.println("[DEBUG] " + message); + } + } + + /** + * 封装debug打印方法(支持格式化) + * @param format 格式化字符串 + * @param args 参数 + */ + private void debugPrint(String format, Object... args) { + if (printDebug) { + System.out.println("[DEBUG] " + String.format(format, args)); + } + } + + /* + * 测试场景:用户正常使用场景,使用get接口进行指定IDC读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testIdcGet1() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:未设置当前IDC进行弱读 + * 测试预期:发到任意follower上进行弱读 + */ + @Test + public void testIdcGet2() throws Exception { + ObTableClient client = newTestClient(); + // client.setCurrentIDC(IDC2); // 未设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:指定了IDC,但是没有指定弱读 + * 测试预期:发到leader副本上进行读取 + */ + @Test + public void testIdcGet3() throws Exception { + ObTableClient client = newTestClient(); + // client.setCurrentIDC(IDC2); // 未设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + // .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置不存在的IDC进行弱读 + * 测试预期:fallback到其他可用的副本(sameRegion或otherRegion) + */ + @Test + public void testIdcGet4() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC("invalid_idc"); // 设置一个不存在的 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且IDC不是invalid_idc + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertNotEquals("invalid_idc", readReplica.getIdc()); + } + + /* + * 测试场景:设置IDC并使用strong consistency + * 测试预期:即使设置了IDC,strong consistency也应该读leader + */ + @Test + public void testIdcGet5() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据,使用strong consistency + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("strong") // 设置强一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:strong consistency应该读leader,即使设置了IDC + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置空字符串IDC进行弱读 + * 测试预期:fallback到其他可用的副本 + */ + @Test + public void testIdcGet6() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(""); // 设置空字符串 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:使用非法的ReadConsistency值 + * 测试预期:抛出IllegalArgumentException异常 + */ + @Test(expected = IllegalArgumentException.class) + public void testIdcGet7() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 使用非法的ReadConsistency值,应该抛出异常 + try { + client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("invalid_consistency") // 非法的consistency值 + .select("c2") + .execute(); + // 如果执行到这里,说明没有抛出异常,测试失败 + Assert.fail("Expected IllegalArgumentException for invalid readConsistency"); + } catch (IllegalArgumentException e) { + debugPrint("Expected exception caught: %s", e.getMessage()); + // 验证异常消息包含相关信息 + Assert.assertTrue(e.getMessage().contains("readConsistency is invalid") + || e.getMessage().contains("invalid_consistency")); + throw e; // 重新抛出异常以满足@Test(expected = IllegalArgumentException.class) + } + } + + /* + * 测试场景:设置IDC但该IDC没有该分区的副本(极端情况) + * 测试预期:fallback到其他region的副本 + */ + @Test + public void testIdcGet8() throws Exception { + ObTableClient client = newTestClient(); + // 假设IDC4不存在于任何zone中 + client.setCurrentIDC("idc4"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc(只设置IDC1, IDC2, IDC3,不设置IDC4) + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且IDC不是idc4 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertNotEquals("idc4", readReplica.getIdc()); + } + + /* + * 测试场景:使用null作为ReadConsistency(使用默认值) + * 测试预期:使用默认的strong consistency,读leader + */ + @Test + public void testIdcGet9() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 不设置ReadConsistency,使用默认值(应该是strong) + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + // 不调用setReadConsistency,使用默认值 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:默认应该是strong,读leader + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置IDC,但使用大小写不同的weak值 + * 测试预期:应该能正常识别(不区分大小写) + */ + @Test + public void testIdcGet10() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 使用不同大小写的weak + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("WEAK") // 大写 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且优先是IDC1 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:使用全局的read consistency level进行读取 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testIdcGet11() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + // 不设置语句级弱一致性读,使用全局的read consistency level + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:设置全局read consistency level为weak,语句级别设置为strong + * 测试预期:以语句级别为准,使用strong consistency level,读leader + */ + @Test + public void testIdcGet12() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("strong") // 语句级别设置为strong,应该覆盖全局的weak + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读leader(因为语句级别设置了strong) + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:用户正常使用场景,使用scan接口进行指定IDC读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testIdcScan1() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("weak") + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:未设置当前IDC进行弱读 + * 测试预期:发到任意follower上进行弱读 + */ + @Test + public void testIdcScan2() throws Exception { + ObTableClient client = newTestClient(); + // client.setCurrentIDC(IDC2); // 未设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:指定了IDC,但是没有指定弱读 + * 测试预期:发到leader副本上进行读取 + */ + @Test + public void testIdcScan3() throws Exception { + ObTableClient client = newTestClient(); + // client.setCurrentIDC(IDC2); // 未设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + // .setReadConsistency("weak") // 不设置弱一致性读 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置不存在的IDC进行弱读 + * 测试预期:fallback到其他可用的副本(sameRegion或otherRegion) + */ + @Test + public void testIdcScan4() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC("invalid_idc"); // 设置一个不存在的 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且IDC不是invalid_idc + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertNotEquals("invalid_idc", readReplica.getIdc()); + } + + /* + * 测试场景:设置IDC并使用strong consistency + * 测试预期:即使设置了IDC,strong consistency也应该读leader + */ + @Test + public void testIdcScan5() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据,使用strong consistency + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("strong") // 设置强一致性读 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:strong consistency应该读leader,即使设置了IDC + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置空字符串IDC进行弱读 + * 测试预期:fallback到其他可用的副本 + */ + @Test + public void testIdcScan6() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(""); // 设置空字符串 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:使用非法的ReadConsistency值 + * 测试预期:抛出IllegalArgumentException异常 + */ + @Test(expected = IllegalArgumentException.class) + public void testIdcScan7() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 使用非法的ReadConsistency值,应该抛出异常 + try { + client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("invalid_consistency") // 非法的consistency值 + .select("c2") + .execute(); + // 如果执行到这里,说明没有抛出异常,测试失败 + Assert.fail("Expected IllegalArgumentException for invalid readConsistency"); + } catch (IllegalArgumentException e) { + debugPrint("Expected exception caught: %s", e.getMessage()); + // 验证异常消息包含相关信息 + Assert.assertTrue(e.getMessage().contains("readConsistency is invalid") + || e.getMessage().contains("invalid_consistency")); + throw e; // 重新抛出异常以满足@Test(expected = IllegalArgumentException.class) + } + } + + /* + * 测试场景:设置IDC但该IDC没有该分区的副本(极端情况) + * 测试预期:fallback到其他region的副本 + */ + @Test + public void testIdcScan8() throws Exception { + ObTableClient client = newTestClient(); + // 假设IDC4不存在于任何zone中 + client.setCurrentIDC("idc4"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc(只设置IDC1, IDC2, IDC3,不设置IDC4) + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("weak") + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且IDC不是idc4 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertNotEquals("idc4", readReplica.getIdc()); + } + + /* + * 测试场景:使用null作为ReadConsistency(使用默认值) + * 测试预期:使用默认的strong consistency,读leader + */ + @Test + public void testIdcScan9() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 不设置ReadConsistency,使用默认值(应该是strong) + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + // 不调用setReadConsistency,使用默认值 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:默认应该是strong,读leader + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置IDC,但使用大小写不同的weak值 + * 测试预期:应该能正常识别(不区分大小写) + */ + @Test + public void testIdcScan10() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 使用不同大小写的weak + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("WEAK") // 大写 + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:设置全局read consistency level为weak,不设置语句级的read consistency + * 测试预期:使用全局的weak consistency level,发到对应的IDC上进行读取 + */ + @Test + public void testIdcScan11() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + // 不设置语句级弱一致性读,使用全局的read consistency level + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:设置全局read consistency level为weak,语句级别设置为strong + * 测试预期:以语句级别为准,使用strong consistency level,读leader + */ + @Test + public void testIdcScan12() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 + QueryResultSet res = client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .setReadConsistency("strong") // 语句级别设置为strong,应该覆盖全局的weak + .select("c2") + .execute(); + while (res.next()) { + Map valueMap = res.getRow(); + Assert.assertEquals("c2_val", valueMap.get("c2")); + } + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读leader(因为语句级别设置了strong) + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:用户正常使用场景,使用batch get接口进行指定IDC读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testIdcBatchGet1() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:未设置当前IDC进行弱读 + * 测试预期:发到任意follower上进行弱读 + */ + @Test + public void testIdcBatchGet2() throws Exception { + ObTableClient client = newTestClient(); + // client.setCurrentIDC(IDC2); // 未设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:指定了IDC,但是没有指定弱读 + * 测试预期:发到leader副本上进行读取 + */ + @Test + public void testIdcBatchGet3() throws Exception { + ObTableClient client = newTestClient(); + // client.setCurrentIDC(IDC2); // 未设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + // .setReadConsistency("weak") // 不设置弱一致性读 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置不存在的IDC进行弱读 + * 测试预期:fallback到其他可用的副本(sameRegion或otherRegion) + */ + @Test + public void testIdcBatchGet4() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC("invalid_idc"); // 设置一个不存在的 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且IDC不是invalid_idc + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertNotEquals("invalid_idc", readReplica.getIdc()); + } + + /* + * 测试场景:设置IDC并使用strong consistency + * 测试预期:即使设置了IDC,strong consistency也应该读leader + */ + @Test + public void testIdcBatchGet5() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据,使用strong consistency + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("strong") // 设置强一致性读 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:strong consistency应该读leader,即使设置了IDC + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置空字符串IDC进行弱读 + * 测试预期:fallback到其他可用的副本 + */ + @Test + public void testIdcBatchGet6() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(""); // 设置空字符串 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") // 设置弱一致性读 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:使用非法的ReadConsistency值 + * 测试预期:抛出IllegalArgumentException异常 + */ + @Test(expected = IllegalArgumentException.class) + public void testIdcBatchGet7() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 使用非法的ReadConsistency值,应该抛出异常 + try { + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("invalid_consistency") // 非法的consistency值 + .select("c2"); + batch.addOperation(get); + batch.execute(); + // 如果执行到这里,说明没有抛出异常,测试失败 + Assert.fail("Expected IllegalArgumentException for invalid readConsistency"); + } catch (IllegalArgumentException e) { + debugPrint("Expected exception caught: %s", e.getMessage()); + // 验证异常消息包含相关信息 + Assert.assertTrue(e.getMessage().contains("readConsistency is invalid") + || e.getMessage().contains("invalid_consistency")); + throw e; // 重新抛出异常以满足@Test(expected = IllegalArgumentException.class) + } + } + + /* + * 测试场景:设置IDC但该IDC没有该分区的副本(极端情况) + * 测试预期:fallback到其他region的副本 + */ + @Test + public void testIdcBatchGet8() throws Exception { + ObTableClient client = newTestClient(); + // 假设IDC4不存在于任何zone中 + client.setCurrentIDC("idc4"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc(只设置IDC1, IDC2, IDC3,不设置IDC4) + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("weak") + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower,且IDC不是idc4 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertNotEquals("idc4", readReplica.getIdc()); + } + + /* + * 测试场景:使用null作为ReadConsistency(使用默认值) + * 测试预期:使用默认的strong consistency,读leader + */ + @Test + public void testIdcBatchGet9() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 不设置ReadConsistency,使用默认值(应该是strong) + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + // 不调用setReadConsistency,使用默认值 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:默认应该是strong,读leader + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置IDC,但使用大小写不同的weak值 + * 测试预期:应该能正常识别(不区分大小写) + */ + @Test + public void testIdcBatchGet10() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 使用不同大小写的weak + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("WEAK") // 大写 + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读到follower + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:设置全局read consistency level为weak,不设置语句级的read consistency + * 测试预期:使用全局的weak consistency level,发到对应的IDC上进行读取 + */ + @Test + public void testIdcBatchGet11() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + // 不设置语句级弱一致性读,使用全局的read consistency level + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:设置全局read consistency level为weak,语句级别设置为strong + * 测试预期:以语句级别为准,使用strong consistency level,读leader + */ + @Test + public void testIdcBatchGet12() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency("strong") // 语句级别设置为strong,应该覆盖全局的weak + .select("c2"); + batch.addOperation(get); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:应该读leader(因为语句级别设置了strong) + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:设置全局read consistency level为weak,执行INSERT操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlInsertWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 2. 执行INSERT操作 + String rowkey = getRandomRowkString(); + client.insert(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "c2_val"))).execute(); + // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, INSERT_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 4. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 5. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } + + /* + * 测试场景:设置全局read consistency level为weak,执行UPDATE操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlUpdateWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(500); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 执行UPDATE操作 + client.update(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "c2_val_updated"))).execute(); + // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, UPDATE_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } + + /* + * 测试场景:设置全局read consistency level为weak,执行DELETE操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlDeleteWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 执行DELETE操作 + client.delete(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))).execute(); + // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, DELETE_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } + + /* + * 测试场景:设置全局read consistency level为weak,执行REPLACE操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlReplaceWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 设置 idc + String rowkey = getRandomRowkString(); + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 2. 执行REPLACE操作 + client.replace(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "c2_val_replaced"))).execute(); + // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, REPLACE_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 4. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 5. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } + + /* + * 测试场景:设置全局read consistency level为weak,执行INSERT_OR_UPDATE操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlInsertOrUpdateWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 设置 idc + String rowkey = getRandomRowkString(); + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 2. 执行INSERT_OR_UPDATE操作 + client.insertOrUpdate(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "c2_val"))).execute(); + // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, INSERT_OR_UPDATE_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 4. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 5. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } + + /* + * 测试场景:设置全局read consistency level为weak,执行PUT操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlPutWithGlobalWeak() throws Exception { + try { + setMinimalImage(tenantConnection); + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 设置 idc + String rowkey = getRandomRowkString(); + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 2. 执行PUT操作 + client.put(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "c2_val_put"))).execute(); + // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, PUT_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 4. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 5. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } catch (Exception e) { + throw e; + } finally { + setFullImage(tenantConnection); + } + } + + /* + * 测试场景:设置全局read consistency level为weak,执行INCREMENT操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlIncrementWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 设置 idc + String rowkey = getRandomRowkString(); + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 2. 执行INCREMENT操作(注意:INCREMENT通常用于数值类型,这里仅测试路由逻辑) + // 由于表结构是varchar,这里可能失败,但我们可以先测试路由 + try { + client.increment(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "1"))).execute(); + // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, INCREMENT_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 4. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 5. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } catch (Exception e) { + // INCREMENT可能因为类型不匹配而失败,但我们可以检查是否有SQL audit记录 + debugPrint("INCREMENT operation failed (expected for varchar type): %s", e.getMessage()); + // 如果操作失败,我们无法验证路由,但至少确认了操作尝试执行 + } + } + + /* + * 测试场景:设置全局read consistency level为weak,执行APPEND操作 + * 测试预期:DML操作应该发到leader,即使全局设置了weak consistency + */ + @Test + public void testDmlAppendWithGlobalWeak() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + // 2. 设置 idc + setZoneIdc(ZONE1, IDC1); + setZoneIdc(ZONE2, IDC2); + setZoneIdc(ZONE3, IDC3); + // 3. 执行APPEND操作 + client.append(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) + .addMutateRow(row(colVal("c2", "_appended"))).execute(); + // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, APPEND_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验:DML操作应该发到leader + ReplicaLocation writeReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("writeReplica: %s", writeReplica.toString()); + Assert.assertTrue(writeReplica.isLeader()); + } + +} diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObWeakReadConsistencyTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObWeakReadConsistencyTest.java deleted file mode 100644 index 8a39a377..00000000 --- a/src/test/java/com/alipay/oceanbase/rpc/ObWeakReadConsistencyTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/*- - * #%L - * OBKV Table Client Framework - * %% - * Copyright (C) 2021 OceanBase - * %% - * OBKV Table Client Framework is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - * #L% - */ - -package com.alipay.oceanbase.rpc; - -import com.alipay.oceanbase.rpc.exception.ObTableUnexpectedException; -import com.alipay.oceanbase.rpc.location.model.*; -import com.alipay.oceanbase.rpc.protocol.payload.ResultCodes; -import com.alipay.oceanbase.rpc.threadlocal.ThreadLocalMap; -import com.alipay.oceanbase.rpc.util.ObTableClientTestUtil; -import com.alipay.oceanbase.rpc.util.ZoneUtil; -import org.junit.*; -import java.util.Map; - -public class ObWeakReadConsistencyTest { - private static final String fullUserName = ObTableClientTestUtil.FULL_USER_NAME; - private static final String password = ObTableClientTestUtil.PASSWORD; - private static final String paramUrl = ObTableClientTestUtil.PARAM_URL; - private static final String weakParamUrl = paramUrl - + "&read_consistency=weak&ob_route_policy=follower_first"; - private static final int dataSetSize = 10; - private static String testIdc = "dev"; - protected ObTableClient client; - - public static void initZoneClient() { - System.setProperty("zmode", "true"); - System.setProperty("com.alipay.confreg.url", "confreg-pool.stable.alipay.net"); - System.setProperty("com.alipay.ldc.zone", "GZ00A"); - } - - public static ObTableClient getObTableClient(String paramUrl) throws Exception { - ObTableClient obTableClient = new ObTableClient(); - obTableClient.setFullUserName(fullUserName); - obTableClient.setParamURL(paramUrl); - obTableClient.setPassword(password); - obTableClient.setCurrentIDC(testIdc); - obTableClient.setSysUserName(ObTableClientTestUtil.PROXY_SYS_USER_NAME); - obTableClient.setSysPassword(ObTableClientTestUtil.PROXY_SYS_USER_PASSWORD); - obTableClient.init(); - return obTableClient; - } - - @BeforeClass - public static void init() throws Exception { - // TODO: this test need refactored - // ThreadLocalMap.setReadConsistency(ObReadConsistency.WEAK); - // cleanup(); - // ObTableClient client = getObTableClient(paramUrl); - // for (int i = 0; i < dataSetSize; i++) { - // String key = "abc-" + i; - // String val = "xyz-" + i; - // client.insert("test_varchar_table", key, new String[] { "c2" }, new String[] { val }); - // } - } - - @AfterClass - public static void cleanup() throws Exception { - // TODO: this test need refactored - return; - // ObTableClient client = getObTableClient(paramUrl); - // for (int i = 0; i < dataSetSize; i++) { - // String key = "abc-" + i; - // client.delete("test_varchar_table", key); - // } - } - - @Before - public void setup() throws Exception { - // client = getObTableClient(weakParamUrl); - } - - @After - public void teardown() throws Exception { - // client.close(); - } - - @Test - public void testReadConsistencySetting() { - // Assert.assertEquals(client.getReadConsistency(), ObReadConsistency.WEAK); - // Assert.assertEquals(client.getObRoutePolicy(), ObRoutePolicy.FOLLOWER_FIRST); - } - - @Test - public void testGetWithWeakRead() throws Exception { - // skip test now - if (true) { - return; - } - - for (int i = 0; i < dataSetSize; i++) { - String key = "abc-" + i; - String val = "xyz-" + i; - try { - Map res = client.get("test_varchar_table", key, new String[] { "c1", "c2" }); - Assert.assertEquals(val, res.get("c2")); - } catch (ObTableUnexpectedException e) { - Assert.fail("failed to get with weak read"); - } - } - Assert.assertFalse(client.getReadConsistency().isStrong()); - } - - @Test - public void testZoneIdc() { - // skip test now - if (true) { - return; - } - Assert.assertEquals("dev", ZoneUtil.getCurrentIDC()); - } -} diff --git a/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableClientTestBase.java b/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableClientTestBase.java index 4a506bc4..ea73acf2 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableClientTestBase.java +++ b/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableClientTestBase.java @@ -51,7 +51,7 @@ public void setClient(Table client) { } public boolean skipObTableTest() { - return this instanceof ObTableTest; + return true; } @After diff --git a/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableTest.java b/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableTest.java deleted file mode 100644 index e933dacf..00000000 --- a/src/test/java/com/alipay/oceanbase/rpc/bolt/ObTableTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/*- - * #%L - * OBKV Table Client Framework - * %% - * Copyright (C) 2021 OceanBase - * %% - * OBKV Table Client Framework is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - * #L% - */ - -package com.alipay.oceanbase.rpc.bolt; - -import com.alipay.oceanbase.rpc.ObTableClient; -import com.alipay.oceanbase.rpc.exception.ObTableException; -import com.alipay.oceanbase.rpc.table.ObTable; -import com.alipay.oceanbase.rpc.table.ObTableClientType; -import com.alipay.oceanbase.rpc.util.ObTableClientTestUtil; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.junit.Assert.*; - -public class ObTableTest extends ObTableClientTestBase { - private ObTable obTable; - - @BeforeClass - static public void beforeTest() throws Exception { - ObTableClient obTableClient = ObTableClientTestUtil.newTestClient(); - obTableClient.init(); - - assertFalse(obTableClient.isOdpMode()); - } - - @Before - public void setup() throws Exception { - ObTableClient obTableClient = ObTableClientTestUtil.newTestClient(); - obTableClient.init(); - - if (obTableClient.isOdpMode()) { - obTableClient.close(); - throw new ObTableException("ODP Mode does not support this test"); - } else { - obTable = obTableClient.getTableParam("test_varchar_table", new Object[] { "abc" }) - .getObTable(); - client = obTable; - } - } - - @Test - public void test_login() throws Exception { - ObTableException obTableException = null; - try { - new ObTable.Builder(obTable.getIp(), obTable.getPort()) // - .setLoginInfo(obTable.getTenantName(), obTable.getUserName(), "11", "test", - ObTableClientType.JAVA_TABLE_CLIENT) // - .build(); - } catch (ObTableException ex) { - obTableException = ex; - } - - assertNotNull(obTableException); - assertTrue(obTableException.getMessage().contains("login failed")); - assertTrue(obTableException.getCause().getMessage().contains("OB_PASSWORD_WRONG")); - - obTableException = null; - try { - new ObTable.Builder(obTable.getIp(), obTable.getPort()) // - .setLoginInfo(obTable.getTenantName(), "root1", "11", "test", - ObTableClientType.JAVA_TABLE_CLIENT) // - .build(); - obTable.get("test_varchar_table", "1", new String[] { "c2" }); - } catch (ObTableException ex) { - obTableException = ex; - } - - assertNotNull(obTableException); - assertTrue(obTableException.getMessage().contains("login failed")); - assertTrue(obTableException.getCause().getMessage().contains("OB_ERR_USER_NOT_EXIST")); - } - -} diff --git a/src/test/java/com/alipay/oceanbase/rpc/hbase/ObHTableTest.java b/src/test/java/com/alipay/oceanbase/rpc/hbase/ObHTableTest.java deleted file mode 100644 index 68da6fdc..00000000 --- a/src/test/java/com/alipay/oceanbase/rpc/hbase/ObHTableTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/*- - * #%L - * OBKV Table Client Framework - * %% - * Copyright (C) 2021 OceanBase - * %% - * OBKV Table Client Framework is licensed under Mulan PSL v2. - * You can use this software according to the terms and conditions of the Mulan PSL v2. - * You may obtain a copy of Mulan PSL v2 at: - * http://license.coscl.org.cn/MulanPSL2 - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, - * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, - * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. - * See the Mulan PSL v2 for more details. - * #L% - */ - -package com.alipay.oceanbase.rpc.hbase; - -import com.alipay.oceanbase.rpc.ObTableClient; -import com.alipay.oceanbase.rpc.exception.ObTableException; -import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableOperationType; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQueryRequest; -import com.alipay.oceanbase.rpc.stream.ObTableClientQueryStreamResult; -import com.alipay.oceanbase.rpc.table.ObTable; -import com.alipay.oceanbase.rpc.util.ObTableClientTestUtil; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.Test; - -import java.util.List; - -import static org.junit.Assert.assertFalse; - -public class ObHTableTest { - private ObTable client; - private ObTableClient obTableClient; - - @BeforeClass - static public void beforeTest() throws Exception { - ObTableClient obTableClient = ObTableClientTestUtil.newTestClient(); - obTableClient.init(); - obTableClient.setRunningMode(ObTableClient.RunningMode.HBASE); - - assertFalse(obTableClient.isOdpMode()); - } - - @Before - public void setup() throws Exception { - ObTableClient obTableClient = ObTableClientTestUtil.newTestClient(); - obTableClient.init(); - if (obTableClient.isOdpMode()) { - obTableClient.close(); - throw new ObTableException("ODP Mode does not support this test"); - } else { - client = obTableClient.getTableParam("test_varchar_table", new Object[] { "abc" }) - .getObTable(); - this.obTableClient = obTableClient; - } - } - - @Test - public void iud() throws Exception { - /* - CREATE TABLE `test_hbase$fn` ( - `K` varbinary(1024) NOT NULL, - `Q` varbinary(256) NOT NULL, - `T` bigint(20) NOT NULL, - `V` varbinary(1024) DEFAULT NULL, - PRIMARY KEY (`K`, `Q`, `T`) - ) - */ - ObHTableOperationRequest hTableOperationRequest = new ObHTableOperationRequest(); - hTableOperationRequest.setOperationType(ObTableOperationType.INSERT); - hTableOperationRequest.setTableName("test_hbase"); - hTableOperationRequest.setFamilyName("fn"); - hTableOperationRequest.setRowKey("key".getBytes()); - hTableOperationRequest.setQualifierName("qualifierName2".getBytes()); - hTableOperationRequest.setValue("value".getBytes()); - - Object obj = client.getRealClient().invokeSync(client.getConnection(), - hTableOperationRequest.obTableOperationRequest(), 1000000); - System.err.println(obj); - - client.delete("test_hbase$fn", new Object[] { "key".getBytes(), - "qualifierName1".getBytes(), 12323121L }); - } - - public byte[][] extractFamilyFromQualifier(byte[] qualifier) throws Exception { - int total_length = qualifier.length; - int familyLen = -1; - byte[][] familyAndQualifier = new byte[2][]; - - for (int i = 0; i < total_length; i++) { - if (qualifier[i] == '\0') { - familyLen = i; - break; - } - } - - byte[] family = new byte[familyLen]; - if (familyLen != -1) { - for (int i = 0; i < familyLen; i++) { - family[i] = qualifier[i]; - } - } else { - throw new RuntimeException("can not get family name"); - } - familyAndQualifier[0] = family; - int qualifierLen = total_length - familyLen - 1; - byte[] newQualifier = new byte[qualifierLen]; - if (qualifierLen > 0) { - for (int i = 0; i < qualifierLen; i++) { - newQualifier[i] = qualifier[i + familyLen + 1]; - } - } else { - throw new RuntimeException("can not get qualifier name"); - } - for (int i = 0; i < qualifierLen; i++) { - newQualifier[i] = qualifier[i + familyLen + 1]; - } - familyAndQualifier[1] = newQualifier; - System.out.println(newQualifier); - System.out.println(family); - return familyAndQualifier; - } - - public void getKeyValueFromResult(ObTableClientQueryStreamResult clientQueryStreamResult, - boolean isTableGroup, byte[] family) throws Exception { - for (List row : clientQueryStreamResult.getCacheRows()) { - System.out.println(new String((byte[]) row.get(0).getValue())); //K - // System.out.println(family); //family - if (isTableGroup) { - byte[][] familyAndQualifier = extractFamilyFromQualifier((byte[]) row.get(1) - .getValue()); - System.out.println(new String(familyAndQualifier[0])); //family - System.out.println(new String(familyAndQualifier[1])); //qualifier - } else { - System.out.println(family); //family - System.out.println(new String((byte[]) row.get(1).getValue())); //qualifier - } - - System.out.println((Long) row.get(2).getValue());//T - System.out.println(new String((byte[]) row.get(3).getValue()));//V - } - } - - @Test - public void hbaseTableGroupTest() throws Exception { - /* - CREATE TABLEGROUP test SHARDING = 'ADAPTIVE'; - CREATE TABLE `test$family1` ( - `K` varbinary(1024) NOT NULL, - `Q` varbinary(256) NOT NULL, - `T` bigint(20) NOT NULL, - `V` varbinary(1024) DEFAULT NULL, - PRIMARY KEY (`K`, `Q`, `T`) - ) TABLEGROUP = test; - */ - byte[] family = new byte[] {}; - ObHTableOperationRequest hTableOperationRequestGet = new ObHTableOperationRequest(); - hTableOperationRequestGet.setOperationType(ObTableOperationType.GET); - hTableOperationRequestGet.setTableName("test"); - hTableOperationRequestGet.setRowKey("putKey".getBytes()); - - ObTableQueryRequest requestGet = (ObTableQueryRequest) hTableOperationRequestGet - .obTableGroupOperationRequest(); - ObTableClientQueryStreamResult clientQueryStreamResultGet = (ObTableClientQueryStreamResult) obTableClient - .execute(requestGet); - - // Thread.currentThread().sleep(30000); - ObHTableOperationRequest hTableOperationRequestScan = new ObHTableOperationRequest(); - hTableOperationRequestScan.setOperationType(ObTableOperationType.SCAN); - hTableOperationRequestScan.setTableName("test"); - hTableOperationRequestScan.setRowKey("putKey".getBytes()); - - ObTableQueryRequest requestScan = (ObTableQueryRequest) hTableOperationRequestScan - .obTableGroupOperationRequest(); - ObTableClientQueryStreamResult clientQueryStreamResultScan = (ObTableClientQueryStreamResult) obTableClient - .execute(requestScan); - - } - - @Test - public void hbaseDiffTableGroupTest() throws Exception { - /* - CREATE TABLEGROUP test SHARDING = 'ADAPTIVE'; - CREATE TABLE `test$family1` ( - `K` varbinary(1024) NOT NULL, - `Q` varbinary(256) NOT NULL, - `T` bigint(20) NOT NULL, - `V` varbinary(1024) DEFAULT NULL, - PRIMARY KEY (`K`, `Q`, `T`) - ) TABLEGROUP = test; - CREATE TABLEGROUP test2 SHARDING = 'ADAPTIVE'; - CREATE TABLE `test2$family1` ( - `K` varbinary(1024) NOT NULL, - `Q` varbinary(256) NOT NULL, - `T` bigint(20) NOT NULL, - `V` varbinary(1024) DEFAULT NULL, - PRIMARY KEY (`K`, `Q`, `T`) - ) TABLEGROUP = test2; - */ - byte[] family = new byte[] {}; - ObHTableOperationRequest hTableOperationRequestGet = new ObHTableOperationRequest(); - hTableOperationRequestGet.setOperationType(ObTableOperationType.GET); - hTableOperationRequestGet.setTableName("test"); - hTableOperationRequestGet.setRowKey("putKey".getBytes()); - - ObTableQueryRequest requestGet = (ObTableQueryRequest) hTableOperationRequestGet - .obTableGroupOperationRequest(); - ObTableClientQueryStreamResult clientQueryStreamResultGet = (ObTableClientQueryStreamResult) obTableClient - .execute(requestGet); - - // Thread.currentThread().sleep(30000); - ObHTableOperationRequest hTableOperationRequestScan = new ObHTableOperationRequest(); - hTableOperationRequestScan.setOperationType(ObTableOperationType.SCAN); - hTableOperationRequestScan.setTableName("test2"); - hTableOperationRequestScan.setRowKey("putKey".getBytes()); - - ObTableQueryRequest requestScan = (ObTableQueryRequest) hTableOperationRequestScan - .obTableGroupOperationRequest(); - ObTableClientQueryStreamResult clientQueryStreamResultScan = (ObTableClientQueryStreamResult) obTableClient - .execute(requestScan); - } - -} diff --git a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java index a8406ca1..4ea774e7 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java @@ -41,12 +41,12 @@ import static com.alipay.oceanbase.rpc.table.ObKVParamsBase.paramType.HBase; public class ObTableLsOperationRequestTest { - private int lsOpReqSize = 10; - private int tabletOpSize = 10; - private int singleOpSize = 10; - private int defaultIterSize = 10; + private int lsOpReqSize = 10; + private int tabletOpSize = 10; + private int singleOpSize = 10; + private int defaultIterSize = 10; - private static final Random random = new Random(); + private static final Random random = new Random(); @Test public void testLsReqEncodePerformance() { @@ -295,21 +295,23 @@ public void testDefaultKVParamsEncode() { perfComparator.printResult("testDefaultKVParamsEncode"); } - private static void assertEncodeByteArray(byte[] bytes1, byte[] bytes2) { - if (bytes1 == bytes2) return; - if (bytes1 == null || bytes2 == null) Assert.fail(); - if (bytes1.length != bytes2.length) Assert.fail(); + if (bytes1 == bytes2) + return; + if (bytes1 == null || bytes2 == null) + Assert.fail(); + if (bytes1.length != bytes2.length) + Assert.fail(); for (int i = 0; i < bytes1.length; i++) { if (bytes1[i] != bytes2[i]) { - System.err.println("byte not equal in index:"+ i + " ,bytes1:" + bytes1[i] + " ,bytes2:" + bytes2[i]); + System.err.println("byte not equal in index:" + i + " ,bytes1:" + bytes1[i] + + " ,bytes2:" + bytes2[i]); Assert.assertEquals(bytes1, bytes2); } } } - private ObTableLSOpRequest buildLsReq() { ObTableLSOpRequest lsOpReq = new ObTableLSOpRequest(); lsOpReq.setCredential(new ObBytesString(generateRandomString(100).getBytes())); @@ -476,6 +478,7 @@ private static ObNewRange buildRandomRange() { return range; } } + class PerformanceComparator { PerformanceCalculator calc1 = new PerformanceCalculator(); PerformanceCalculator calc2 = new PerformanceCalculator(); @@ -508,7 +511,8 @@ public void printResult(String msg) { if (!calc2.isValid() && !calc1.isValid()) { System.out.println("not valid results"); } - System.out.println("==========================================================================="); + System.out + .println("==========================================================================="); } } @@ -546,7 +550,7 @@ public double getAverageTime() { } public void printResults(String msg) { - System.out.println(msg + ": \n\taverage execution time: " + getAverageTime() + " ns"); + System.out.println(msg + ": \n\taverage execution time: " + getAverageTime() + " ns"); } public void clear() { diff --git a/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java b/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java index 5771dc5a..47ee95db 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java @@ -19,8 +19,12 @@ import com.alipay.oceanbase.rpc.ObTableClient; import com.alipay.oceanbase.rpc.bolt.ObTableClientTestBase; +import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.property.Property; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; import com.alipay.oceanbase.rpc.util.ObTableClientTestUtil; +import static com.alipay.oceanbase.rpc.mutation.MutationFactory.*; + import org.junit.Before; import org.junit.Test; @@ -75,8 +79,9 @@ public void testConnectionPoolSize() throws Exception { assertEquals(TEST_CONNECTION_POOL_SIZE, obTableClient.getOdpTable() .getObTableConnectionPoolSize()); } else { - ObTableParam param = obTableClient.getTableParamWithRoute("test_varchar_table", - new String[] { "abc" }, obTableClient.getRoute(false)); + Row rowKey = row(colVal("c1", "abc")); + ObTableParam param = obTableClient.getTableRoute().getTableParam("test_varchar_table", + rowKey, ObTableConsistencyLevel.STRONG); int poolSize = param.getObTable().getObTableConnectionPoolSize(); assertEquals(TEST_CONNECTION_POOL_SIZE, poolSize); } @@ -107,8 +112,9 @@ public void testWatermarkSetting() throws Exception { assertEquals(TEST_NETTY_WAIT_INTERVAL, obTableClient.getOdpTable() .getNettyBlockingWaitInterval()); } else { - ObTableParam param = obTableClient.getTableParamWithRoute("test_varchar_table", - new String[] { "abc" }, obTableClient.getRoute(false)); + Row rowKey = row(colVal("c1", "abc")); + ObTableParam param = obTableClient.getTableRoute().getTableParam("test_varchar_table", + rowKey, ObTableConsistencyLevel.STRONG); int lowWatermark = param.getObTable().getNettyBufferLowWatermark(); int highWatermark = param.getObTable().getNettyBufferHighWatermark(); int waitInterval = param.getObTable().getNettyBlockingWaitInterval(); @@ -129,8 +135,9 @@ public void testDefaultWatermark() throws Exception { if (obTableClient.isOdpMode()) { // do nothing } else { - ObTableParam param = obTableClient.getTableParamWithRoute("test_varchar_table", - new String[] { "abc" }, obTableClient.getRoute(false)); + Row rowKey = row(colVal("c1", "abc")); + ObTableParam param = obTableClient.getTableRoute().getTableParam("test_varchar_table", + rowKey, ObTableConsistencyLevel.STRONG); int lowWatermark = param.getObTable().getNettyBufferLowWatermark(); int highWatermark = param.getObTable().getNettyBufferHighWatermark(); int waitInterval = param.getObTable().getNettyBlockingWaitInterval(); From 58d5ec472c3d00759354034b60b3e24bd4f89df7 Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Thu, 27 Nov 2025 14:44:12 +0800 Subject: [PATCH 03/10] modify weak read interface (#412) --- .../oceanbase/rpc/ObClusterTableQuery.java | 5 +- .../alipay/oceanbase/rpc/ObTableClient.java | 56 ++++----- .../com/alipay/oceanbase/rpc/get/Get.java | 20 ++-- .../rpc/location/model/TableRoute.java | 32 +++--- .../model/partition/ObPartitionLocation.java | 6 +- .../rpc/mutation/BatchOperation.java | 18 +-- ...tencyLevel.java => ObReadConsistency.java} | 17 +-- .../ObTableAbstractOperationRequest.java | 6 +- .../execute/ObTableBatchOperationRequest.java | 2 +- .../impl/execute/ObTableLSOpRequest.java | 6 +- .../impl/execute/ObTableOperationRequest.java | 2 +- .../query/AbstractQueryStreamResult.java | 6 +- .../execute/query/ObTableQueryRequest.java | 4 +- .../rpc/table/AbstractTableQuery.java | 7 +- .../rpc/table/ObTableClientBatchOpsImpl.java | 6 +- .../table/ObTableClientLSBatchOpsImpl.java | 10 +- .../rpc/table/ObTableClientQueryImpl.java | 24 ++-- .../oceanbase/rpc/table/api/TableQuery.java | 5 +- .../oceanbase/rpc/ObTableWeakReadTest.java | 107 ++++++++---------- .../ObTableBatchOperationRequestTest.java | 4 +- .../ObTableLsOperationRequestTest.java | 2 +- .../execute/ObTableOperationRequestTest.java | 8 +- .../query/ObTableQueryPayloadTest.java | 4 +- .../rpc/table/ObTableConnectionTest.java | 8 +- 24 files changed, 171 insertions(+), 194 deletions(-) rename src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/{ObTableConsistencyLevel.java => ObReadConsistency.java} (74%) diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java index 172f7782..036b2646 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObClusterTableQuery.java @@ -20,6 +20,7 @@ import com.alipay.oceanbase.rpc.location.model.partition.Partition; import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.aggregation.ObTableAggregationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObHTableFilter; @@ -272,7 +273,7 @@ public TableQuery setSearchText(String searchText) { } @Override - public TableQuery setReadConsistency(String readConsistency) { + public TableQuery setReadConsistency(ObReadConsistency readConsistency) { // 同时设置父类和内部 tableClientQuery 的 readConsistency super.setReadConsistency(readConsistency); tableClientQuery.setReadConsistency(readConsistency); @@ -280,7 +281,7 @@ public TableQuery setReadConsistency(String readConsistency) { } @Override - public String getReadConsistency() { + public ObReadConsistency getReadConsistency() { // 返回内部 tableClientQuery 的 readConsistency return tableClientQuery.getReadConsistency(); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java index 6f981e70..740531e5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java @@ -408,7 +408,7 @@ private T execute(String tableName, TableExecuteCallback callback) throws /** * Execute with a route strategy. */ - private T execute(String tableName, TableExecuteCallback callback, ObTableConsistencyLevel currentConsistencyLevel) + private T execute(String tableName, TableExecuteCallback callback, ObReadConsistency currentConsistencyLevel) throws Exception { if (tableName == null || tableName.isEmpty()) { throw new IllegalArgumentException("table name is null"); @@ -617,7 +617,7 @@ private T execute(String tableName, OperationExecuteCallback callback) * Execute with a route strategy for mutation */ private T execute(String tableName, OperationExecuteCallback callback, - ObTableConsistencyLevel currentConsistencyLevel) throws Exception { + ObReadConsistency currentConsistencyLevel) throws Exception { if (tableName == null || tableName.isEmpty()) { throw new IllegalArgumentException("table name is null"); } @@ -1105,7 +1105,7 @@ public Map get(final String tableName, final Object[] rowKey, throw new IllegalArgumentException("table name is null"); } final long startTime = System.currentTimeMillis(); - final ObTableConsistencyLevel readConsistency = tableRoute.getReadConsistency(); + final ObReadConsistency readConsistency = tableRoute.getReadConsistency(); return execute(tableName, new TableExecuteCallback>(rowKey) { @Override public Map execute(ObTableParam tableParam) throws Exception { @@ -1167,7 +1167,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1206,7 +1206,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1247,7 +1247,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1283,7 +1283,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1324,7 +1324,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1363,7 +1363,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1396,7 +1396,7 @@ public Map get(final String tableName, final Row rowKey, * @throws Exception exception */ public Map get(final String tableName, final Row rowKey, - final String[] selectColumns, final ObTableConsistencyLevel readConsistency) throws Exception { + final String[] selectColumns, final ObReadConsistency readConsistency) throws Exception { final long start = System.currentTimeMillis(); return execute(tableName, new OperationExecuteCallback>(rowKey, null) { @@ -1410,7 +1410,7 @@ public Map execute(ObTableParam tableParam) throws Exception { ObTableOperationRequest request = ObTableOperationRequest.getInstance( tableName, GET, rowKey.getValues(), selectColumns, null, obTable.getObTableOperationTimeout()); - ObTableConsistencyLevel consistencyLevel = readConsistency; + ObReadConsistency consistencyLevel = readConsistency; if (readConsistency == null) { // when readConsistency is not set, use the global read consistency level consistencyLevel = tableRoute.getReadConsistency(); } @@ -1465,7 +1465,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1506,7 +1506,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1545,7 +1545,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1586,7 +1586,7 @@ public Long execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getAffectedRows(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1629,7 +1629,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1688,7 +1688,7 @@ public Map execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getEntity().getSimpleProperties(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1733,7 +1733,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1770,7 +1770,7 @@ public Map execute(ObTableParam tableParam) throws Exception { checkObTableOperationResult(obTable.getIp(), obTable.getPort(), request, result); return ((ObTableOperationResult) result).getEntity().getSimpleProperties(); } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -1809,7 +1809,7 @@ public ObPayload execute(ObTableParam tableParam) throws Exception { checkResult(obTable.getIp(), obTable.getPort(), request, result); return result; } - }, ObTableConsistencyLevel.STRONG); + }, ObReadConsistency.STRONG); } /** @@ -2149,8 +2149,8 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E ObTableClientQueryImpl tableQuery = new ObTableClientQueryImpl(tableName, ((ObTableQueryRequest) request).getTableQuery(), this); tableQuery.setEntityType(request.getEntityType()); - if (request.getConsistencyLevel() == ObTableConsistencyLevel.EVENTUAL) { - tableQuery.setReadConsistency("weak"); + if (request.getConsistencyLevel() == ObReadConsistency.WEAK) { + tableQuery.setReadConsistency(ObReadConsistency.WEAK); } tableQuery.setHbaseOpType(request.getHbaseOpType()); return new ObClusterTableQuery(tableQuery).executeInternal(); @@ -2160,8 +2160,8 @@ public ObPayload execute(final ObTableAbstractOperationRequest request) throws E ObTableClientQueryImpl tableQuery = new ObTableClientQueryImpl(tableName, ((ObTableQueryAsyncRequest) request).getObTableQueryRequest().getTableQuery(), this); tableQuery.setEntityType(request.getEntityType()); - if (request.getConsistencyLevel() == ObTableConsistencyLevel.EVENTUAL) { - tableQuery.setReadConsistency("weak"); + if (request.getConsistencyLevel() == ObReadConsistency.WEAK) { + tableQuery.setReadConsistency(ObReadConsistency.WEAK); } tableQuery.setHbaseOpType(request.getHbaseOpType()); ObClusterTableQuery clusterTableQuery = new ObClusterTableQuery(tableQuery); @@ -2551,7 +2551,7 @@ public void setParamURL(String paramURL) throws IllegalArgumentException { BOOT.info(String.format("will set database=%s", kv[1])); } } else if (Constants.READ_CONSISTENCY.equalsIgnoreCase(kv[0])) { - tableRoute.setReadConsistency(kv[1]); + tableRoute.setReadConsistency(ObReadConsistency.getByName(kv[1])); if (BOOT.isInfoEnabled()) { BOOT.info(String.format("will set %s=%s", Constants.READ_CONSISTENCY, kv[1])); } @@ -2754,7 +2754,7 @@ public ObTableClientType getClientType(RunningMode runningMode) { } } - public void setReadConsistency(String readConsistency) throws IllegalArgumentException { + public void setReadConsistency(ObReadConsistency readConsistency) throws IllegalArgumentException { tableRoute.setReadConsistency(readConsistency); } @@ -2762,8 +2762,8 @@ public String getReadConsistency() { return tableRoute.getReadConsistency().name(); } - public void setRoutePolicy(String policy) throws IllegalArgumentException { - tableRoute.setRoutePolicy(ObRoutePolicy.getByName(policy)); + public void setRoutePolicy(ObRoutePolicy policy) throws IllegalArgumentException { + tableRoute.setRoutePolicy(policy); } public ObTableServerCapacity getServerCapacity() { diff --git a/src/main/java/com/alipay/oceanbase/rpc/get/Get.java b/src/main/java/com/alipay/oceanbase/rpc/get/Get.java index d3e04aab..2cce598a 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/get/Get.java +++ b/src/main/java/com/alipay/oceanbase/rpc/get/Get.java @@ -20,17 +20,17 @@ import com.alipay.oceanbase.rpc.ObTableClient; import com.alipay.oceanbase.rpc.mutation.ColumnValue; import com.alipay.oceanbase.rpc.mutation.Row; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.table.api.Table; import java.util.Map; public class Get { - private Table client = null; - private String tableName = null; - private Row rowKey = null; - private String[] selectColumns = null; - private String readConsistency = ""; + private Table client = null; + private String tableName = null; + private Row rowKey = null; + private String[] selectColumns = null; + private ObReadConsistency readConsistency = null; public Get(Table client, String tableName) { this.client = client; @@ -62,12 +62,12 @@ public Get select(String... columns) { return this; } - public Get setReadConsistency(String readConsistency) { + public Get setReadConsistency(ObReadConsistency readConsistency) { this.readConsistency = readConsistency; return this; } - public String getReadConsistency() { + public ObReadConsistency getReadConsistency() { return readConsistency; } @@ -76,10 +76,6 @@ public String[] getSelectColumns() { } public Map execute() throws Exception { - ObTableConsistencyLevel readConsistency = null; - if (this.readConsistency != null && !this.readConsistency.isEmpty()) { - readConsistency = ObTableConsistencyLevel.getByName(this.readConsistency); - } if (client == null) { throw new IllegalArgumentException("client is null"); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java index 520c5225..a9d754fa 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java @@ -25,7 +25,7 @@ import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObRowKey; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObBorderFlag; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObNewRange; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQuery; @@ -56,7 +56,7 @@ public class TableRoute { private volatile ServerRoster serverRoster = null; // all servers which contain current tenant private volatile ConfigServerInfo configServerInfo = null; // rslist private volatile TableRoster tableRoster = null; // table mean connection pool here - private ObTableConsistencyLevel consistencyLevel = ObTableConsistencyLevel.STRONG; // global read consistency level + private ObReadConsistency consistencyLevel = ObReadConsistency.STRONG; // global read consistency level private String currentIDC = null; // current client IDC for weak read routing private ObRoutePolicy routePolicy = ObRoutePolicy.FOLLOWER_FIRST; // route policy for weak read private TableLocations tableLocations = null; // map[tableName, TableEntry] @@ -150,7 +150,7 @@ public ObRoutePolicy getRoutePolicy() { * Get read consistency level. * @return read consistency level */ - public ObTableConsistencyLevel getReadConsistency() { + public ObReadConsistency getReadConsistency() { return this.consistencyLevel; } @@ -158,8 +158,8 @@ public ObTableConsistencyLevel getReadConsistency() { * Set read consistency level. * @param readConsistency read consistency level */ - public void setReadConsistency(String readConsistency) throws IllegalArgumentException { - this.consistencyLevel = ObTableConsistencyLevel.getByName(readConsistency); + public void setReadConsistency(ObReadConsistency readConsistency) throws IllegalArgumentException { + this.consistencyLevel = readConsistency; } public OdpInfo getOdpInfo() { @@ -743,7 +743,7 @@ public ObTableParam getTableParam(String tableName, Row rowkey) throws Exception } public ObTableParam getTableParam(String tableName, Row rowkey, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws Exception { TableEntry tableEntry = getTableEntry(tableName); if (tableEntry == null) { @@ -761,7 +761,7 @@ public ObTableParam getTableParam(String tableName, Row rowkey, * @param currentConsistencyLevel current consistency level * @return ObTableParam tableParam * */ - public List getTableParams(String tableName, List rowkeys, ObTableConsistencyLevel currentConsistencyLevel) throws Exception { + public List getTableParams(String tableName, List rowkeys, ObReadConsistency currentConsistencyLevel) throws Exception { TableEntry tableEntry = getTableEntry(tableName); if (tableEntry == null) { logger.error("tableEntry is null, tableName: {}", tableName); @@ -869,7 +869,7 @@ public Map getPartIdParamMapForQuery(String tableName, * @throws Exception exception */ public ObTableParam getTableWithPartId(String tableName, long partId, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws Exception { // route parameter is kept for backward compatibility but not used TableEntry tableEntry = getTableEntry(tableName); @@ -886,7 +886,7 @@ public ObTableParam getTableWithPartId(String tableName, long partId, * @throws Exception exception */ private ObTableParam getTableInternal(String tableName, TableEntry tableEntry, long partId, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws Exception { ReplicaLocation replica = null; long tabletId = getTabletIdByPartId(tableEntry, partId); @@ -954,10 +954,10 @@ private ObTableParam getTableInternal(String tableName, TableEntry tableEntry, l } private ReplicaLocation getPartitionLocation(ObPartitionLocationInfo locationInfo, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws ObTableException { ObPartitionLocation partitionLocation = locationInfo.getPartitionLocation(); - ObTableConsistencyLevel level = currentConsistencyLevel; + ObReadConsistency level = currentConsistencyLevel; // when currentConsistencyLevel is null, we use global consistencyLevel if (level == null) { level = this.consistencyLevel; @@ -992,7 +992,7 @@ private ObTableParam createTableParam(ObTable obTable, TableEntry tableEntry, */ public ObTableParam getTableParam(String tableName, List scanRangeColumns, ObNewRange keyRange, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws Exception { Map tabletIdIdMapObTable = new HashMap(); ObRowKey startKey = keyRange.getStartKey(); @@ -1050,7 +1050,7 @@ public ObTableParam getTableParam(String tableName, List scanRangeColumn */ public ObTableParam getTableParam(String tableName, List scanRangeColumns, List keyRanges, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws Exception { Map partIdIdMapObTable = getPartIdParamMapForQuery(tableName, scanRangeColumns, keyRanges); @@ -1081,7 +1081,7 @@ public ObTableParam getTableParam(String tableName, List scanRangeColumn public List getTableParams(String tableName, ObTableQuery query, Object[] start, boolean startInclusive, Object[] end, boolean endInclusive, - ObTableConsistencyLevel currentConsistencyLevel) + ObReadConsistency currentConsistencyLevel) throws Exception { // route parameter is kept for backward compatibility but not used return getTablesInternal(tableName, query.getScanRangeColumns(), start, startInclusive, @@ -1091,7 +1091,7 @@ public List getTableParams(String tableName, ObTableQuery query, O private List getTablesInternal(String tableName, List scanRangeColumns, Object[] start, boolean startInclusive, Object[] end, boolean endInclusive, - ObTableConsistencyLevel currentConsistencyLevel) throws Exception { + ObReadConsistency currentConsistencyLevel) throws Exception { // route parameter is kept for backward compatibility but not used if (start.length != end.length) { throw new IllegalArgumentException("length of start key and end key is not equal"); @@ -1157,7 +1157,7 @@ private List> getPartitionReplica(TableEntry table boolean startIncluded, Row endRow, boolean endIncluded, - ObTableConsistencyLevel currentConsistencyLevel) throws Exception { + ObReadConsistency currentConsistencyLevel) throws Exception { // route parameter is kept for backward compatibility but not used List> replicas = new ArrayList<>(); List partIds = getPartIds(tableEntry, startRow, startIncluded, endRow, endIncluded); diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java index e2c6f754..0efe70c7 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java @@ -18,7 +18,7 @@ package com.alipay.oceanbase.rpc.location.model.partition; import com.alipay.oceanbase.rpc.location.model.*; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import java.util.ArrayList; import java.util.Collections; @@ -74,10 +74,10 @@ public void addReplicaLocation(ReplicaLocation replica) { * @param route * @return */ - public ReplicaLocation getReplica(ObTableConsistencyLevel consistencyLevel, + public ReplicaLocation getReplica(ObReadConsistency consistencyLevel, ObRoutePolicy routePolicy) throws IllegalArgumentException { // strong read : read leader - if (consistencyLevel == null || consistencyLevel == ObTableConsistencyLevel.STRONG) { + if (consistencyLevel == null || consistencyLevel == ObReadConsistency.STRONG) { return leader; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java index c6b58487..ca02e48e 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java @@ -23,7 +23,7 @@ import com.alipay.oceanbase.rpc.exception.ObTableException; import com.alipay.oceanbase.rpc.get.Get; import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObObj; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.OHOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; @@ -317,18 +317,12 @@ private BatchOperationResult executeWithNormalBatchOp() throws Exception { return new BatchOperationResult(batchOps.executeWithResult()); } - private boolean checkReadConsistency(ObTableClient obTableClient, String readConsistency) throws IllegalArgumentException { - // 如果没有设置语句级别的 readConsistency(空串或null),使用 TableRoute 上的 consistencyLevel - if (readConsistency == null || readConsistency.isEmpty()) { - return obTableClient.getTableRoute().getReadConsistency() == ObTableConsistencyLevel.EVENTUAL; - } - if (readConsistency.equalsIgnoreCase("weak")) { - return true; - } else if (readConsistency.equalsIgnoreCase("strong")) { - return false; - } else { - throw new IllegalArgumentException("readConsistency is invalid: " + readConsistency); + private boolean checkReadConsistency(ObTableClient obTableClient, ObReadConsistency readConsistency) throws IllegalArgumentException { + // 如果没有设置语句级别的 readConsistency(null),使用 TableRoute 上的 consistencyLevel + if (readConsistency == null) { + return obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; } + return readConsistency == ObReadConsistency.WEAK; } private BatchOperationResult executeWithLSBatchOp() throws Exception { diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObReadConsistency.java similarity index 74% rename from src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java rename to src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObReadConsistency.java index f6d84a6e..3901ff62 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableConsistencyLevel.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObReadConsistency.java @@ -20,26 +20,26 @@ import java.util.HashMap; import java.util.Map; -public enum ObTableConsistencyLevel { +public enum ObReadConsistency { - STRONG(0), EVENTUAL(1); + STRONG(0), WEAK(1); private int value; - private static Map map = new HashMap(); + private static Map map = new HashMap(); - ObTableConsistencyLevel(int value) { + ObReadConsistency(int value) { this.value = value; } static { - for (ObTableConsistencyLevel type : ObTableConsistencyLevel.values()) { + for (ObReadConsistency type : ObReadConsistency.values()) { map.put(type.value, type); } } - public static ObTableConsistencyLevel getByName(String name) throws IllegalArgumentException { + public static ObReadConsistency getByName(String name) throws IllegalArgumentException { if (name.equalsIgnoreCase("weak")) { - return EVENTUAL; + return WEAK; } else if (name.equalsIgnoreCase("strong")) { return STRONG; } else { @@ -50,7 +50,7 @@ public static ObTableConsistencyLevel getByName(String name) throws IllegalArgum /* * Value of. */ - public static ObTableConsistencyLevel valueOf(int value) { + public static ObReadConsistency valueOf(int value) { return map.get(value); } @@ -69,3 +69,4 @@ public byte getByteValue() { } } + diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java index 309f7318..f5efd54f 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableAbstractOperationRequest.java @@ -35,7 +35,7 @@ public abstract class ObTableAbstractOperationRequest extends AbstractPayload im protected long tableId = Constants.OB_INVALID_ID; // table id. 如果知道表id,可以用于优化,如果不知道,设定为OB_INVALID_ID protected long partitionId = Constants.INVALID_TABLET_ID; // Constants.OB_INVALID_ID; // partition id / tabletId. 如果知道表分区id,可以用于优化,如果不知道,设定为OB_INVALID_ID protected ObTableEntityType entityType = ObTableEntityType.KV; // entity type. 如果明确entity类型,可以用于优化,如果不知道,设定为ObTableEntityType::DYNAMIC - protected ObTableConsistencyLevel consistencyLevel = ObTableConsistencyLevel.STRONG; // read consistency level. 读一致性,是否要强一致性等(必须读到刚写入的数据). 目前只支持STRONG. + protected ObReadConsistency consistencyLevel = ObReadConsistency.STRONG; // read consistency level. 读一致性 protected ObTableOptionFlag option_flag = ObTableOptionFlag.DEFAULT; protected boolean returningAffectedEntity = false; protected boolean returningAffectedRows = false; @@ -191,14 +191,14 @@ public void setEntityType(ObTableEntityType entityType) { /* * Get consistency level. */ - public ObTableConsistencyLevel getConsistencyLevel() { + public ObReadConsistency getConsistencyLevel() { return consistencyLevel; } /* * Set consistency level. */ - public void setConsistencyLevel(ObTableConsistencyLevel consistencyLevel) { + public void setConsistencyLevel(ObReadConsistency consistencyLevel) { this.consistencyLevel = consistencyLevel; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequest.java index 25eeca53..df8da504 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequest.java @@ -113,7 +113,7 @@ public Object decode(ByteBuf buf) { this.batchOperation = new ObTableBatchOperation(); this.batchOperation.decode(buf); - this.consistencyLevel = ObTableConsistencyLevel.valueOf(buf.readByte()); + this.consistencyLevel = ObReadConsistency.valueOf(buf.readByte()); this.option_flag = ObTableOptionFlag.valueOf(buf.readByte()); this.returningAffectedEntity = Serialization.decodeI8(buf) != 0; this.returningAffectedRows = Serialization.decodeI8(buf) != 0; diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java index a8589155..90e1d925 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLSOpRequest.java @@ -39,7 +39,7 @@ public class ObTableLSOpRequest extends AbstractPayload implements Credentialable { protected ObBytesString credential; protected ObTableEntityType entityType = ObTableEntityType.KV; - protected ObTableConsistencyLevel consistencyLevel = ObTableConsistencyLevel.STRONG; + protected ObReadConsistency consistencyLevel = ObReadConsistency.STRONG; private ObTableLSOperation lsOperation = null; protected OHOperationType hbaseOpType = OHOperationType.INVALID; @@ -90,7 +90,7 @@ public Object decode(ByteBuf buf) { super.decode(buf); this.credential = Serialization.decodeBytesString(buf); this.entityType = ObTableEntityType.valueOf(buf.readByte()); - this.consistencyLevel = ObTableConsistencyLevel.valueOf(buf.readByte()); + this.consistencyLevel = ObReadConsistency.valueOf(buf.readByte()); this.lsOperation = new ObTableLSOperation(); this.lsOperation.decode(buf); @@ -151,7 +151,7 @@ public void setTimeout(long timeout) { /* * Set consistency level. */ - public void setConsistencyLevel(ObTableConsistencyLevel consistencyLevel) { + public void setConsistencyLevel(ObReadConsistency consistencyLevel) { this.consistencyLevel = consistencyLevel; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequest.java index 3fe9c97a..a152c4a5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequest.java @@ -105,7 +105,7 @@ public Object decode(ByteBuf buf) { } this.tableOperation.decode(buf); - this.consistencyLevel = ObTableConsistencyLevel.valueOf(buf.readByte()); + this.consistencyLevel = ObReadConsistency.valueOf(buf.readByte()); this.option_flag = ObTableOptionFlag.valueOf(buf.readByte()); this.returningAffectedEntity = Serialization.decodeI8(buf) != 0; this.returningAffectedRows = Serialization.decodeI8(buf) != 0; diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java index 8c1c42c5..387d6577 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/AbstractQueryStreamResult.java @@ -65,7 +65,7 @@ public abstract class AbstractQueryStreamResult extends AbstractPayload implemen protected List cacheProperties = new LinkedList(); protected LinkedList> cacheRows = new LinkedList>(); private LinkedList, ObTableQueryResult>> partitionLastResult = new LinkedList, ObTableQueryResult>>(); - private ObTableConsistencyLevel readConsistency = ObTableConsistencyLevel.STRONG; + private ObReadConsistency readConsistency = ObReadConsistency.STRONG; // ObRowKey objs: [startKey, MIN_OBJECT, MIN_OBJECT] public List currentStartKey; protected ObTableClient client; @@ -794,7 +794,7 @@ public void setExpectant(Map> expectant) { /* * Get Read Consistency */ - public ObTableConsistencyLevel getReadConsistency() { + public ObReadConsistency getReadConsistency() { return readConsistency; } @@ -803,7 +803,7 @@ public ObTableConsistencyLevel getReadConsistency() { * * @param readConsistency */ - public void setReadConsistency(ObTableConsistencyLevel readConsistency) { + public void setReadConsistency(ObReadConsistency readConsistency) { this.readConsistency = readConsistency; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java index 3382b4f5..3789622b 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryRequest.java @@ -20,7 +20,7 @@ import com.alipay.oceanbase.rpc.ObGlobal; import com.alipay.oceanbase.rpc.protocol.payload.Pcodes; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableAbstractOperationRequest; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.util.Serialization; import io.netty.buffer.ByteBuf; @@ -99,7 +99,7 @@ public Object decode(ByteBuf buf) { else this.partitionId = Serialization.decodeVi64(buf); this.entityType = ObTableEntityType.valueOf(buf.readByte()); - this.consistencyLevel = ObTableConsistencyLevel.valueOf(buf.readByte()); + this.consistencyLevel = ObReadConsistency.valueOf(buf.readByte()); this.tableQuery = new ObTableQuery(); this.tableQuery.decode(buf); diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java index 99f94156..2508de47 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/AbstractTableQuery.java @@ -20,6 +20,7 @@ import com.alipay.oceanbase.rpc.exception.ObTableException; import com.alipay.oceanbase.rpc.filter.ObTableFilter; import com.alipay.oceanbase.rpc.mutation.Row; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.table.api.TableQuery; @@ -31,16 +32,16 @@ public abstract class AbstractTableQuery implements TableQuery { protected ObTableEntityType entityType = ObTableEntityType.KV; protected long operationTimeout = -1; - protected String readConsistency = ""; // 空串表示用户没有设置,将使用 TableRoute 上的 consistencyLevel + protected ObReadConsistency readConsistency = null; // null 表示用户没有设置,将使用 TableRoute 上的 consistencyLevel @Override - public TableQuery setReadConsistency(String readConsistency) { + public TableQuery setReadConsistency(ObReadConsistency readConsistency) { this.readConsistency = readConsistency; return this; } @Override - public String getReadConsistency() { + public ObReadConsistency getReadConsistency() { return readConsistency; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java index 457dd020..1e2e37ed 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java @@ -297,9 +297,9 @@ public void partitionExecute(ObTableOperationResult[] results, if (batchOperation.isReadOnly()) { // 如果设置了 isWeakRead,使用弱读;否则使用全局的 readConsistency if (isWeakRead) { - subRequest.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + subRequest.setConsistencyLevel(ObReadConsistency.WEAK); } else { - subRequest.setConsistencyLevel(ObTableConsistencyLevel.STRONG); + subRequest.setConsistencyLevel(ObReadConsistency.STRONG); } } subRequest.setBatchOperationAsAtomic(isAtomicOperation()); @@ -342,7 +342,7 @@ public void partitionExecute(ObTableOperationResult[] results, obTableClient.getTabletIdByPartId(entry, originPartId)); ObTableParam newParam = obTableClient.getTableRoute() .getTableWithPartId(tableName, originPartId, - ObTableConsistencyLevel.STRONG); + ObReadConsistency.STRONG); subObTable = newParam.getObTable(); subRequest.setPartitionId(newParam.getPartitionId()); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java index 5915e1ad..6962efc4 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientLSBatchOpsImpl.java @@ -449,7 +449,7 @@ public LsOperationsMap prepareOperations(BatchIdxOperationPairList operationsWit private LsOperationsMap prepareByFirstOperation(LsOperationsMap lsOperationsMap, BatchIdxOperationPairList operationsWithIndex) throws Exception { - ObTableConsistencyLevel consistencyLevel = isWeakRead ? ObTableConsistencyLevel.EVENTUAL : ObTableConsistencyLevel.STRONG; + ObReadConsistency consistencyLevel = isWeakRead ? ObReadConsistency.WEAK : ObReadConsistency.STRONG; if (operationsWithIndex.isEmpty()) { throw new IllegalArgumentException("batch operations is empty"); } else { @@ -490,7 +490,7 @@ private LsOperationsMap prepareByFirstOperation(LsOperationsMap lsOperationsMap, private LsOperationsMap prepareByEachOperation(LsOperationsMap lsOperationsMap, BatchIdxOperationPairList operationsWithIndex) throws Exception { - ObTableConsistencyLevel consistencyLevel = isWeakRead ? ObTableConsistencyLevel.EVENTUAL : ObTableConsistencyLevel.STRONG; + ObReadConsistency consistencyLevel = isWeakRead ? ObReadConsistency.WEAK : ObReadConsistency.STRONG; for (int i = 0; i < operationsWithIndex.size(); i++) { ObPair operation = operationsWithIndex.get(i); Row rowKey = calculateRowKey(operation); @@ -602,9 +602,9 @@ public void partitionExecute(ObTableSingleOpResult[] results, tableLsOpRequest.setEntityType(entityType); tableLsOpRequest.setTimeout(operationTimeout); if (isWeakRead) { - tableLsOpRequest.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + tableLsOpRequest.setConsistencyLevel(ObReadConsistency.WEAK); } else { - tableLsOpRequest.setConsistencyLevel(ObTableConsistencyLevel.STRONG); + tableLsOpRequest.setConsistencyLevel(ObReadConsistency.STRONG); } tableLsOpRequest.setHbaseOpType(hbaseOpType); @@ -636,7 +636,7 @@ public void partitionExecute(ObTableSingleOpResult[] results, if (tryTimes > 1) { if (needRefreshPartitionLocation) { // refresh partition location - ObTableConsistencyLevel consistencyLevel = isWeakRead ? ObTableConsistencyLevel.EVENTUAL : ObTableConsistencyLevel.STRONG; + ObReadConsistency consistencyLevel = isWeakRead ? ObReadConsistency.WEAK : ObReadConsistency.STRONG; TableEntry entry = obTableClient.getOrRefreshTableEntry(realTableName, false); obTableClient.refreshTableLocationByTabletId(realTableName, obTableClient.getTabletIdByPartId(entry, originPartId)); ObTableParam param = obTableClient.getTableRoute().getTableWithPartId(realTableName, originPartId, consistencyLevel); diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java index e931300b..3d366c88 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientQueryImpl.java @@ -27,7 +27,7 @@ import com.alipay.oceanbase.rpc.protocol.payload.ObPayload; import com.alipay.oceanbase.rpc.protocol.payload.ResultCodes; import com.alipay.oceanbase.rpc.protocol.payload.impl.ObRowKey; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.OHOperationType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.aggregation.ObTableAggregationType; @@ -155,7 +155,7 @@ public void checkArgumentBeforeExec() throws Exception { /* * Set parameter into request */ - private void setCommonParams2Result(AbstractQueryStreamResult result, ObTableConsistencyLevel actualReadConsistency) throws Exception { + private void setCommonParams2Result(AbstractQueryStreamResult result, ObReadConsistency actualReadConsistency) throws Exception { result.setTableQuery(tableQuery); result.setEntityType(entityType); result.setTableName(tableName); @@ -167,7 +167,7 @@ private void setCommonParams2Result(AbstractQueryStreamResult result, ObTableCon } private abstract static class InitQueryResultCallback { - abstract T execute(ObTableConsistencyLevel actualReadConsistency) throws Exception; + abstract T execute(ObReadConsistency actualReadConsistency) throws Exception; } private AbstractQueryStreamResult commonExecute(InitQueryResultCallback callable) @@ -177,12 +177,12 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback>(); // partitionObTables -> Map> - // 如果没有设置语句级别的 readConsistency(空串或null),使用 TableRoute 上的 consistencyLevel - ObTableConsistencyLevel actualReadConsistency; - if (readConsistency == null || readConsistency.isEmpty()) { + // 如果没有设置语句级别的 readConsistency(null),使用 TableRoute 上的 consistencyLevel + ObReadConsistency actualReadConsistency; + if (readConsistency == null) { actualReadConsistency = obTableClient.getTableRoute().getReadConsistency(); } else { - actualReadConsistency = ObTableConsistencyLevel.getByName(readConsistency); + actualReadConsistency = readConsistency; } // fill a whole range if no range is added explicitly. @@ -294,7 +294,7 @@ private AbstractQueryStreamResult commonExecute(InitQueryResultCallback() { @Override - ObTableClientQueryStreamResult execute(ObTableConsistencyLevel actualReadConsistency) throws Exception { + ObTableClientQueryStreamResult execute(ObReadConsistency actualReadConsistency) throws Exception { ObTableClientQueryStreamResult obTableClientQueryStreamResult = new ObTableClientQueryStreamResult(); setCommonParams2Result(obTableClientQueryStreamResult, actualReadConsistency); obTableClientQueryStreamResult.setClient(obTableClient); @@ -307,7 +307,7 @@ ObTableClientQueryStreamResult execute(ObTableConsistencyLevel actualReadConsist public ObTableClientQueryAsyncStreamResult asyncExecuteInternal() throws Exception { return (ObTableClientQueryAsyncStreamResult) commonExecute(new InitQueryResultCallback() { @Override - ObTableClientQueryAsyncStreamResult execute(ObTableConsistencyLevel actualReadConsistency) throws Exception { + ObTableClientQueryAsyncStreamResult execute(ObReadConsistency actualReadConsistency) throws Exception { ObTableClientQueryAsyncStreamResult obTableClientQueryAsyncStreamResult = new ObTableClientQueryAsyncStreamResult(); obTableClientQueryAsyncStreamResult.setAllowDistributeScan(allowDistributeScan); setCommonParams2Result(obTableClientQueryAsyncStreamResult, actualReadConsistency); @@ -318,7 +318,7 @@ ObTableClientQueryAsyncStreamResult execute(ObTableConsistencyLevel actualReadCo }); } - public Map> initFirstPartition(ObTableQuery tableQuery, String tableName, ObTableConsistencyLevel actualReadConsistency) throws Exception { + public Map> initFirstPartition(ObTableQuery tableQuery, String tableName, ObReadConsistency actualReadConsistency) throws Exception { Map> partitionObTables = new LinkedHashMap<>(); String indexName = tableQuery.getIndexName(); @@ -352,7 +352,7 @@ public Map> initFirstPartition(ObTableQuery tab return partitionObTables; } - public Map> initPartitions(ObTableQuery tableQuery, String tableName, ObTableConsistencyLevel actualReadConsistency) throws Exception { + public Map> initPartitions(ObTableQuery tableQuery, String tableName, ObReadConsistency actualReadConsistency) throws Exception { // partitionObTables -> > Map> partitionObTables = new LinkedHashMap<>(); String indexName = tableQuery.getIndexName(); @@ -402,7 +402,7 @@ public Map> initPartitions(ObTableQuery tableQu /* * Init partition tables involved in this query */ - public void initPartitions(ObTableConsistencyLevel actualReadConsistency) throws Exception { + public void initPartitions(ObReadConsistency actualReadConsistency) throws Exception { if (obTableClient.getServerCapacity().isSupportDistributedExecute()) { this.partitionObTables = initFirstPartition(tableQuery, tableName, actualReadConsistency); } else { diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java index c59ac536..8423c51b 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/api/TableQuery.java @@ -19,6 +19,7 @@ import com.alipay.oceanbase.rpc.filter.ObTableFilter; import com.alipay.oceanbase.rpc.mutation.Row; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObHTableFilter; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query.ObTableQuery; @@ -199,7 +200,7 @@ public interface TableQuery { TableQuery setSearchText(String searchText); - TableQuery setReadConsistency(String readConsistency); + TableQuery setReadConsistency(ObReadConsistency readConsistency); - String getReadConsistency(); + ObReadConsistency getReadConsistency(); } diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java index 88ef462f..56e870a1 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java @@ -28,6 +28,7 @@ import com.alipay.oceanbase.rpc.get.Get; import com.alipay.oceanbase.rpc.mutation.BatchOperation; import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.stream.QueryResultSet; import org.junit.After; @@ -488,7 +489,7 @@ public void testIdcGet1() throws Exception { // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -525,7 +526,7 @@ public void testIdcGet2() throws Exception { // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -562,7 +563,7 @@ public void testIdcGet3() throws Exception { // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - // .setReadConsistency("weak") // 设置弱一致性读 + // .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -599,7 +600,7 @@ public void testIdcGet4() throws Exception { // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -637,7 +638,7 @@ public void testIdcGet5() throws Exception { // 3. 获取数据,使用strong consistency Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("strong") // 设置强一致性读 + .setReadConsistency(ObReadConsistency.STRONG) // 设置强一致性读 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -674,7 +675,7 @@ public void testIdcGet6() throws Exception { // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -710,12 +711,7 @@ public void testIdcGet7() throws Exception { setZoneIdc(ZONE3, IDC3); // 3. 使用非法的ReadConsistency值,应该抛出异常 try { - client.get(TABLE_NAME) - .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("invalid_consistency") // 非法的consistency值 - .select("c2") - .execute(); - // 如果执行到这里,说明没有抛出异常,测试失败 + ObReadConsistency.getByName("invalid_consistency"); // 非法的consistency值 Assert.fail("Expected IllegalArgumentException for invalid readConsistency"); } catch (IllegalArgumentException e) { debugPrint("Expected exception caught: %s", e.getMessage()); @@ -747,7 +743,7 @@ public void testIdcGet8() throws Exception { // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") + .setReadConsistency(ObReadConsistency.WEAK) .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -822,7 +818,7 @@ public void testIdcGet10() throws Exception { // 3. 使用不同大小写的weak Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("WEAK") // 大写 + .setReadConsistency(ObReadConsistency.WEAK) // 大写 .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -846,7 +842,7 @@ public void testIdcGet10() throws Exception { @Test public void testIdcGet11() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -884,7 +880,7 @@ public void testIdcGet11() throws Exception { @Test public void testIdcGet12() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -898,7 +894,7 @@ public void testIdcGet12() throws Exception { // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("strong") // 语句级别设置为strong,应该覆盖全局的weak + .setReadConsistency(ObReadConsistency.STRONG) // 语句级别设置为strong,应该覆盖全局的weak .select("c2") .execute(); debugPrint("c2_val: %s", result.get("c2")); @@ -936,7 +932,7 @@ public void testIdcScan1() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("weak") + .setReadConsistency(ObReadConsistency.WEAK) .select("c2") .execute(); while (res.next()) { @@ -976,7 +972,7 @@ public void testIdcScan2() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); while (res.next()) { @@ -1016,7 +1012,7 @@ public void testIdcScan3() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - // .setReadConsistency("weak") // 不设置弱一致性读 + // .setReadConsistency(ObReadConsistency.WEAK) // 不设置弱一致性读 .select("c2") .execute(); while (res.next()) { @@ -1056,7 +1052,7 @@ public void testIdcScan4() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); while (res.next()) { @@ -1097,7 +1093,7 @@ public void testIdcScan5() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("strong") // 设置强一致性读 + .setReadConsistency(ObReadConsistency.STRONG) // 设置强一致性读 .select("c2") .execute(); while (res.next()) { @@ -1137,7 +1133,7 @@ public void testIdcScan6() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2") .execute(); while (res.next()) { @@ -1175,13 +1171,7 @@ public void testIdcScan7() throws Exception { setZoneIdc(ZONE3, IDC3); // 3. 使用非法的ReadConsistency值,应该抛出异常 try { - client.query(TABLE_NAME) - .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) - .setScanRangeColumns("c1") - .setReadConsistency("invalid_consistency") // 非法的consistency值 - .select("c2") - .execute(); - // 如果执行到这里,说明没有抛出异常,测试失败 + ObReadConsistency.getByName("invalid_consistency"); // 非法的consistency值 Assert.fail("Expected IllegalArgumentException for invalid readConsistency"); } catch (IllegalArgumentException e) { debugPrint("Expected exception caught: %s", e.getMessage()); @@ -1214,7 +1204,7 @@ public void testIdcScan8() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("weak") + .setReadConsistency(ObReadConsistency.WEAK) .select("c2") .execute(); while (res.next()) { @@ -1295,7 +1285,7 @@ public void testIdcScan10() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("WEAK") // 大写 + .setReadConsistency(ObReadConsistency.WEAK) // 大写 .select("c2") .execute(); while (res.next()) { @@ -1321,7 +1311,7 @@ public void testIdcScan10() throws Exception { @Test public void testIdcScan11() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -1362,7 +1352,7 @@ public void testIdcScan11() throws Exception { @Test public void testIdcScan12() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -1377,7 +1367,7 @@ public void testIdcScan12() throws Exception { QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) .setScanRangeColumns("c1") - .setReadConsistency("strong") // 语句级别设置为strong,应该覆盖全局的weak + .setReadConsistency(ObReadConsistency.STRONG) // 语句级别设置为strong,应该覆盖全局的weak .select("c2") .execute(); while (res.next()) { @@ -1417,7 +1407,7 @@ public void testIdcBatchGet1() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1457,7 +1447,7 @@ public void testIdcBatchGet2() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1497,7 +1487,7 @@ public void testIdcBatchGet3() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - // .setReadConsistency("weak") // 不设置弱一致性读 + // .setReadConsistency(ObReadConsistency.WEAK) // 不设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1537,7 +1527,7 @@ public void testIdcBatchGet4() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1578,7 +1568,7 @@ public void testIdcBatchGet5() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("strong") // 设置强一致性读 + .setReadConsistency(ObReadConsistency.STRONG) // 设置强一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1618,7 +1608,7 @@ public void testIdcBatchGet6() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") // 设置弱一致性读 + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1656,14 +1646,7 @@ public void testIdcBatchGet7() throws Exception { setZoneIdc(ZONE3, IDC3); // 3. 使用非法的ReadConsistency值,应该抛出异常 try { - BatchOperation batch = client.batchOperation(TABLE_NAME); - Get get = client.get(TABLE_NAME) - .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("invalid_consistency") // 非法的consistency值 - .select("c2"); - batch.addOperation(get); - batch.execute(); - // 如果执行到这里,说明没有抛出异常,测试失败 + ObReadConsistency.getByName("invalid_consistency"); // 非法的consistency值 Assert.fail("Expected IllegalArgumentException for invalid readConsistency"); } catch (IllegalArgumentException e) { debugPrint("Expected exception caught: %s", e.getMessage()); @@ -1696,7 +1679,7 @@ public void testIdcBatchGet8() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("weak") + .setReadConsistency(ObReadConsistency.WEAK) .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1777,7 +1760,7 @@ public void testIdcBatchGet10() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("WEAK") // 大写 + .setReadConsistency(ObReadConsistency.WEAK) // 大写 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1803,7 +1786,7 @@ public void testIdcBatchGet10() throws Exception { @Test public void testIdcBatchGet11() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -1844,7 +1827,7 @@ public void testIdcBatchGet11() throws Exception { @Test public void testIdcBatchGet12() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -1859,7 +1842,7 @@ public void testIdcBatchGet12() throws Exception { BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency("strong") // 语句级别设置为strong,应该覆盖全局的weak + .setReadConsistency(ObReadConsistency.STRONG) // 语句级别设置为strong,应该覆盖全局的weak .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1885,7 +1868,7 @@ public void testIdcBatchGet12() throws Exception { @Test public void testDmlInsertWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 设置 idc @@ -1915,7 +1898,7 @@ public void testDmlInsertWithGlobalWeak() throws Exception { @Test public void testDmlUpdateWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -1948,7 +1931,7 @@ public void testDmlUpdateWithGlobalWeak() throws Exception { @Test public void testDmlDeleteWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 @@ -1979,7 +1962,7 @@ public void testDmlDeleteWithGlobalWeak() throws Exception { @Test public void testDmlReplaceWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 设置 idc @@ -2009,7 +1992,7 @@ public void testDmlReplaceWithGlobalWeak() throws Exception { @Test public void testDmlInsertOrUpdateWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 设置 idc @@ -2041,7 +2024,7 @@ public void testDmlPutWithGlobalWeak() throws Exception { try { setMinimalImage(tenantConnection); ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 设置 idc @@ -2076,7 +2059,7 @@ public void testDmlPutWithGlobalWeak() throws Exception { @Test public void testDmlIncrementWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 设置 idc @@ -2113,7 +2096,7 @@ public void testDmlIncrementWithGlobalWeak() throws Exception { @Test public void testDmlAppendWithGlobalWeak() throws Exception { ObTableClient client = newTestClient(); - client.setReadConsistency("weak"); // 设置全局的read consistency level为weak + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 准备数据 diff --git a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequestTest.java b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequestTest.java index 3e85fc1f..b3c7e65f 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequestTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableBatchOperationRequestTest.java @@ -34,7 +34,7 @@ public void test_all() { request.setCredential(new ObBytesString("123".getBytes())); request.setTableName("name"); request.setTableId(456); - request.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + request.setConsistencyLevel(ObReadConsistency.WEAK); ObTableBatchOperation obTableBatchOperation = new ObTableBatchOperation(); request.setBatchOperation(obTableBatchOperation); @@ -87,7 +87,7 @@ public void test_all() { assertEquals(new String("123".getBytes()), new String(deRequest.getCredential().bytes)); assertEquals("name", deRequest.getTableName()); - assertEquals(ObTableConsistencyLevel.EVENTUAL, deRequest.getConsistencyLevel()); + assertEquals(ObReadConsistency.WEAK, deRequest.getConsistencyLevel()); assertEquals(2, deRequest.getBatchOperation().getTableOperations().size()); assertEquals(ObTableOperationType.INSERT, deRequest.getBatchOperation() .getTableOperations().get(0).getOperationType()); diff --git a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java index 4ea774e7..f30cde03 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableLsOperationRequestTest.java @@ -315,7 +315,7 @@ private static void assertEncodeByteArray(byte[] bytes1, byte[] bytes2) { private ObTableLSOpRequest buildLsReq() { ObTableLSOpRequest lsOpReq = new ObTableLSOpRequest(); lsOpReq.setCredential(new ObBytesString(generateRandomString(100).getBytes())); - lsOpReq.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + lsOpReq.setConsistencyLevel(ObReadConsistency.WEAK); buildLsOperation(); lsOpReq.setLsOperation(buildLsOperation()); lsOpReq.setTableId(50001); diff --git a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequestTest.java b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequestTest.java index b555e5b3..d5b820e8 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequestTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/ObTableOperationRequestTest.java @@ -34,7 +34,7 @@ public void test_all() { request.setCredential(new ObBytesString("123".getBytes())); request.setTableName("name"); request.setTableId(456); - request.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + request.setConsistencyLevel(ObReadConsistency.WEAK); ObTableOperation obTableOperation = new ObTableOperation(); obTableOperation.setOperationType(ObTableOperationType.INSERT); request.setTableOperation(obTableOperation); @@ -63,7 +63,7 @@ public void test_all() { assertEquals(new String("123".getBytes()), new String(deRequest.getCredential().bytes)); assertEquals("name", deRequest.getTableName()); - assertEquals(ObTableConsistencyLevel.EVENTUAL, deRequest.getConsistencyLevel()); + assertEquals(ObReadConsistency.WEAK, deRequest.getConsistencyLevel()); assertEquals(ObTableOperationType.INSERT, deRequest.getTableOperation().getOperationType()); ObITableEntity deEntity = deRequest.getTableOperation().getEntity(); @@ -101,7 +101,7 @@ public void test_noProperties() { request.setCredential(new ObBytesString("123".getBytes())); request.setTableName("name"); request.setTableId(456); - request.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + request.setConsistencyLevel(ObReadConsistency.WEAK); ObTableOperation obTableOperation = new ObTableOperation(); obTableOperation.setOperationType(ObTableOperationType.INSERT); request.setTableOperation(obTableOperation); @@ -123,7 +123,7 @@ public void test_noProperties() { assertEquals(new String("123".getBytes()), new String(deRequest.getCredential().bytes)); assertEquals("name", deRequest.getTableName()); - assertEquals(ObTableConsistencyLevel.EVENTUAL, deRequest.getConsistencyLevel()); + assertEquals(ObReadConsistency.WEAK, deRequest.getConsistencyLevel()); assertEquals(ObTableOperationType.INSERT, deRequest.getTableOperation().getOperationType()); ObITableEntity deEntity = deRequest.getTableOperation().getEntity(); diff --git a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryPayloadTest.java b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryPayloadTest.java index bc1cde01..8b6903e8 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryPayloadTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryPayloadTest.java @@ -18,7 +18,7 @@ package com.alipay.oceanbase.rpc.protocol.payload.impl.execute.query; import com.alipay.oceanbase.rpc.protocol.payload.impl.*; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableEntityType; import com.alipay.oceanbase.rpc.table.ObFTSParams; import com.alipay.oceanbase.rpc.table.ObHBaseParams; @@ -109,7 +109,7 @@ public void test_ObTableQueryRequest() { obTableQueryRequest.setTableId(200); obTableQueryRequest.setPartitionId(100); obTableQueryRequest.setEntityType(ObTableEntityType.KV); - obTableQueryRequest.setConsistencyLevel(ObTableConsistencyLevel.EVENTUAL); + obTableQueryRequest.setConsistencyLevel(ObReadConsistency.WEAK); byte[] bytes = obTableQueryRequest.encode(); ByteBuf buf = PooledByteBufAllocator.DEFAULT.buffer(); diff --git a/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java b/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java index 47ee95db..fb6f6433 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/table/ObTableConnectionTest.java @@ -21,7 +21,7 @@ import com.alipay.oceanbase.rpc.bolt.ObTableClientTestBase; import com.alipay.oceanbase.rpc.mutation.Row; import com.alipay.oceanbase.rpc.property.Property; -import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObTableConsistencyLevel; +import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.util.ObTableClientTestUtil; import static com.alipay.oceanbase.rpc.mutation.MutationFactory.*; @@ -81,7 +81,7 @@ public void testConnectionPoolSize() throws Exception { } else { Row rowKey = row(colVal("c1", "abc")); ObTableParam param = obTableClient.getTableRoute().getTableParam("test_varchar_table", - rowKey, ObTableConsistencyLevel.STRONG); + rowKey, ObReadConsistency.STRONG); int poolSize = param.getObTable().getObTableConnectionPoolSize(); assertEquals(TEST_CONNECTION_POOL_SIZE, poolSize); } @@ -114,7 +114,7 @@ public void testWatermarkSetting() throws Exception { } else { Row rowKey = row(colVal("c1", "abc")); ObTableParam param = obTableClient.getTableRoute().getTableParam("test_varchar_table", - rowKey, ObTableConsistencyLevel.STRONG); + rowKey, ObReadConsistency.STRONG); int lowWatermark = param.getObTable().getNettyBufferLowWatermark(); int highWatermark = param.getObTable().getNettyBufferHighWatermark(); int waitInterval = param.getObTable().getNettyBlockingWaitInterval(); @@ -137,7 +137,7 @@ public void testDefaultWatermark() throws Exception { } else { Row rowKey = row(colVal("c1", "abc")); ObTableParam param = obTableClient.getTableRoute().getTableParam("test_varchar_table", - rowKey, ObTableConsistencyLevel.STRONG); + rowKey, ObReadConsistency.STRONG); int lowWatermark = param.getObTable().getNettyBufferLowWatermark(); int highWatermark = param.getObTable().getNettyBufferHighWatermark(); int waitInterval = param.getObTable().getNettyBlockingWaitInterval(); From 7d5b54cd3fcd90123fc18aa2be1fa595e6b4b6de Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Thu, 27 Nov 2025 15:58:43 +0800 Subject: [PATCH 04/10] recover Get default construction function (#413) --- src/main/java/com/alipay/oceanbase/rpc/get/Get.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/alipay/oceanbase/rpc/get/Get.java b/src/main/java/com/alipay/oceanbase/rpc/get/Get.java index 2cce598a..43f8a1c5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/get/Get.java +++ b/src/main/java/com/alipay/oceanbase/rpc/get/Get.java @@ -32,6 +32,14 @@ public class Get { private String[] selectColumns = null; private ObReadConsistency readConsistency = null; + public Get() { + this.client = null; + this.tableName = null; + this.rowKey = null; + this.selectColumns = null; + this.readConsistency = null; + } + public Get(Table client, String tableName) { this.client = client; this.tableName = tableName; From 544831dc17f0ef73691cef2c296f520a078e1ff6 Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:45:26 +0800 Subject: [PATCH 05/10] fix read policy (#414) --- .../alipay/oceanbase/rpc/ObTableClient.java | 4 +- .../rpc/location/model/TableRoute.java | 2 +- .../model/partition/ObPartitionLocation.java | 22 +- .../oceanbase/rpc/ObTableWeakReadTest.java | 385 +++++++++++------- 4 files changed, 266 insertions(+), 147 deletions(-) diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java index 740531e5..3f71128d 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java @@ -2754,7 +2754,7 @@ public ObTableClientType getClientType(RunningMode runningMode) { } } - public void setReadConsistency(ObReadConsistency readConsistency) throws IllegalArgumentException { + public void setReadConsistency(ObReadConsistency readConsistency) { tableRoute.setReadConsistency(readConsistency); } @@ -2762,7 +2762,7 @@ public String getReadConsistency() { return tableRoute.getReadConsistency().name(); } - public void setRoutePolicy(ObRoutePolicy policy) throws IllegalArgumentException { + public void setRoutePolicy(ObRoutePolicy policy) { tableRoute.setRoutePolicy(policy); } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java index a9d754fa..8e2b1068 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/TableRoute.java @@ -158,7 +158,7 @@ public ObReadConsistency getReadConsistency() { * Set read consistency level. * @param readConsistency read consistency level */ - public void setReadConsistency(ObReadConsistency readConsistency) throws IllegalArgumentException { + public void setReadConsistency(ObReadConsistency readConsistency) { this.consistencyLevel = readConsistency; } diff --git a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java index 0efe70c7..af337160 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/location/model/partition/ObPartitionLocation.java @@ -104,26 +104,38 @@ private ReplicaLocation getReadReplicaNoLdc(ObRoutePolicy routePolicy) { private ReplicaLocation getReadReplicaByRoutePolicy(ObRoutePolicy routePolicy) throws IllegalArgumentException { + // 路由策略优先:FOLLOWER_FIRST 优先选择 follower,FOLLOWER_ONLY 只能选择 follower + // 在满足路由策略的前提下,按就近原则选择(同机房 -> 同 region -> 其他 region) + + // 优先在同机房找 follower for (ReplicaLocation r : sameIdc) { - if (r.isValid()) { + if (r.isValid() && !r.isLeader()) { return r; } } + + // 如果同机房没有 follower,在同 region 找 follower for (ReplicaLocation r : sameRegion) { - if (r.isValid()) { + if (r.isValid() && !r.isLeader()) { return r; } } + + // 如果同 region 没有 follower,在其他 region 找 follower for (ReplicaLocation r : otherRegion) { - if (r.isValid()) { + if (r.isValid() && !r.isLeader()) { return r; } } - + + // 如果都没有找到 follower if (routePolicy == ObRoutePolicy.FOLLOWER_ONLY) { + // FOLLOWER_ONLY 必须选择 follower,没有就抛出异常 throw new IllegalArgumentException("No follower replica found for route policy: " - + routePolicy); + + routePolicy); } + + // 如果都没有找到,返回 leader(兜底) return leader; } diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java index 56e870a1..881adbeb 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java @@ -26,6 +26,7 @@ import com.alipay.oceanbase.rpc.exception.ObTableException; import com.alipay.oceanbase.rpc.get.Get; +import com.alipay.oceanbase.rpc.location.model.ObRoutePolicy; import com.alipay.oceanbase.rpc.mutation.BatchOperation; import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; @@ -162,13 +163,16 @@ public class ObTableWeakReadTest { private static String PROXY_SYS_USER_NAME = "root"; private static String PROXY_SYS_USER_PASSWORD = ""; private static boolean USE_ODP = false; - private static String ODP_IP = "ip-addr"; - private static int ODP_PORT = 0; - private static String ODP_DATABASE = "database-name"; + private static String ODP_IP = ""; + private static int ODP_SQL_PORT = 2883; + private static int ODP_RPC_PORT = 2885; + private static String ODP_DATABASE = "test"; + private static String JDBC_DATABASE = "test"; private static String JDBC_IP = ""; private static String JDBC_PORT = ""; - private static String JDBC_URL = "jdbc:mysql://"+JDBC_IP+":"+JDBC_PORT+"/test?rewriteBatchedStatements=TRUE&allowMultiQueries=TRUE&useLocalSessionState=TRUE&useUnicode=TRUE&characterEncoding=utf-8&socketTimeout=30000000&connectTimeout=600000&sessionVariables=ob_query_timeout=60000000000"; - + private static String JDBC_URL = "jdbc:mysql://"+JDBC_IP+":"+JDBC_PORT+"/"+JDBC_DATABASE+"?rewriteBatchedStatements=TRUE&allowMultiQueries=TRUE&useLocalSessionState=TRUE&useUnicode=TRUE&characterEncoding=utf-8&socketTimeout=30000000&connectTimeout=600000&sessionVariables=ob_query_timeout=60000000000"; + private static String JDBC_PROXY_URL = "jdbc:mysql://"+ODP_IP+":"+ODP_SQL_PORT+"/"+JDBC_DATABASE+"?rewriteBatchedStatements=TRUE&allowMultiQueries=TRUE&useLocalSessionState=TRUE&useUnicode=TRUE&characterEncoding=utf-8&socketTimeout=30000000&connectTimeout=600000&sessionVariables=ob_query_timeout=60000000000"; + private static boolean printDebug = true; private static int SQL_AUDIT_PERSENT = 20; private static String TENANT_NAME = "mysql"; @@ -180,6 +184,9 @@ public class ObTableWeakReadTest { private static String IDC1 = "idc1"; private static String IDC2 = "idc2"; private static String IDC3 = "idc3"; + private static String REGION1 = "region1"; + private static String REGION2 = "region2"; + private static String REGION3 = "region3"; private static String GET_STMT_TYPE = "KV_GET"; private static String SCAN_STMT_TYPE = "KV_QUERY"; private static String BATCH_GET_STMT_TYPE = "KV_MULTI_GET"; @@ -203,8 +210,12 @@ public class ObTableWeakReadTest { + "WHERE t.table_name = ? AND t.tenant_id = ? AND t.tablet_id = ?;"; private static String SET_SQL_AUDIT_PERSENT_SQL = "SET GLOBAL ob_sql_audit_percentage =?;"; private static String GET_TENANT_ID_SQL = "SELECT tenant_id FROM oceanbase.__all_tenant WHERE tenant_name = ?"; + private static String SET_IDC_SQL = "ALTER PROXYCONFIG SET proxy_idc_name = ?;"; + private static String SET_ROUTE_POLICY_SQL = "ALTER PROXYCONFIG SET proxy_route_policy = ?;"; private Connection tenantConnection = null; private Connection sysConnection = null; + private Connection proxyConnection = null; + private static Connection staticProxyConnection = null; private static Connection staticTenantConnection = null; private static Connection staticSysConnection = null; private static int staticTenantId = 0; @@ -225,7 +236,7 @@ private static ObTableClient newTestClient() throws Exception { obTableClient.setOdpMode(true); obTableClient.setFullUserName(FULL_USER_NAME); obTableClient.setOdpAddr(ODP_IP); - obTableClient.setOdpPort(ODP_PORT); + obTableClient.setOdpPort(ODP_RPC_PORT); obTableClient.setDatabase(ODP_DATABASE); obTableClient.setPassword(PASSWORD); } @@ -247,11 +258,32 @@ private static Connection getSysConnection() throws SQLException { return DriverManager.getConnection(JDBC_URL, "root@sys", PASSWORD); } + /** + * 获取代理连接 + */ + private static Connection getProxyConnection() throws SQLException { + if (USE_ODP) { + // ODP 连接需要包含集群信息的用户名 + // FULL_USER_NAME 格式: user@tenant#cluster + // 对于代理连接,使用 root@sys#cluster 格式 + String[] parts = FULL_USER_NAME.split("#"); + String clusterName = parts.length > 1 ? parts[1] : ""; + String proxyUserName = PROXY_SYS_USER_NAME + "@sys"; + if (!clusterName.isEmpty()) { + proxyUserName += "#" + clusterName; + } + return DriverManager.getConnection(JDBC_PROXY_URL, proxyUserName, PROXY_SYS_USER_PASSWORD); + } else { + return null; + } + } + @org.junit.BeforeClass public static void beforeClass() throws Exception { // 所有测试用例执行前创建表和连接(只执行一次) staticTenantConnection = getConnection(); staticSysConnection = getSysConnection(); + staticProxyConnection = getProxyConnection(); staticTenantId = getTenantId(staticSysConnection); createTable(staticTenantConnection); setSqlAuditPersent(staticTenantConnection, SQL_AUDIT_PERSENT); @@ -268,6 +300,7 @@ public static void afterClass() throws Exception { public void setup() throws Exception { tenantConnection = staticTenantConnection; sysConnection = staticSysConnection; + proxyConnection = staticProxyConnection; tenant_id = staticTenantId; } @@ -301,6 +334,7 @@ private static void cleanupAllData(Connection connection) throws Exception { private static void setMinimalImage(Connection connection) throws Exception { Statement statement = connection.createStatement(); statement.execute("SET GLOBAL binlog_row_image=MINIMAL"); + Thread.sleep(5000); } private static void setFullImage(Connection connection) throws Exception { @@ -328,6 +362,19 @@ private void setZoneIdc(String zone, String idc) throws Exception { statement.execute(); } + private void setZoneRegion(String zone, String region) throws Exception { + PreparedStatement statement = sysConnection.prepareStatement("ALTER SYSTEM MODIFY ZONE ? SET REGION = ?;"); + statement.setString(1, zone); + statement.setString(2, region); + debugPrint("setZoneRegion SQL: %s", statement.toString()); + statement.execute(); + } + + private void setZoneRegionIdc(String zone, String region, String idc) throws Exception { + setZoneRegion(zone, region); + setZoneIdc(zone, idc); + } + // 通过当前纳秒时间戳生成随机字符串 private String getRandomRowkString() { return System.nanoTime() + ""; @@ -469,6 +516,26 @@ private void debugPrint(String format, Object... args) { } } + private void setIdc(ObTableClient client, String idc) throws Exception { + if (USE_ODP) { + PreparedStatement statement = proxyConnection.prepareStatement(SET_IDC_SQL); + statement.setString(1, idc); + statement.execute(); + } else { + client.setCurrentIDC(idc); + } + } + + private void setRoutePolicy(ObTableClient client, String routePolicy) throws Exception { + if (USE_ODP) { + PreparedStatement statement = proxyConnection.prepareStatement(SET_ROUTE_POLICY_SQL); + statement.setString(1, routePolicy); + statement.execute(); + } else { + client.setRoutePolicy(ObRoutePolicy.getByName(routePolicy)); + } + } + /* * 测试场景:用户正常使用场景,使用get接口进行指定IDC读 * 测试预期:发到对应的IDC上进行读取 @@ -476,16 +543,17 @@ private void debugPrint(String format, Object... args) { @Test public void testIdcGet1() throws Exception { ObTableClient client = newTestClient(); - client.setCurrentIDC(IDC2); // 设置当前 idc + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 client.init(); // 1. 准备数据 String rowkey = getRandomRowkString(); insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -506,6 +574,45 @@ public void testIdcGet1() throws Exception { Assert.assertEquals(IDC2, readReplica.getIdc()); } + /* + * 测试场景:同城弱读,读到follower + * 测试预期:读到follower + */ + @Test + public void testIdcGet1_1() throws Exception { + ObTableClient client = newTestClient(); + setIdc(client, IDC1); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION1, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 + .select("c2") + .execute(); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + /* * 测试场景:未设置当前IDC进行弱读 * 测试预期:发到任意follower上进行弱读 @@ -520,9 +627,9 @@ public void testIdcGet2() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -557,9 +664,9 @@ public void testIdcGet3() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -594,9 +701,9 @@ public void testIdcGet4() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -632,9 +739,9 @@ public void testIdcGet5() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,使用strong consistency Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -669,9 +776,9 @@ public void testIdcGet6() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -706,9 +813,9 @@ public void testIdcGet7() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用非法的ReadConsistency值,应该抛出异常 try { ObReadConsistency.getByName("invalid_consistency"); // 非法的consistency值 @@ -737,9 +844,9 @@ public void testIdcGet8() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc(只设置IDC1, IDC2, IDC3,不设置IDC4) - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -775,9 +882,9 @@ public void testIdcGet9() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 不设置ReadConsistency,使用默认值(应该是strong) Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -812,9 +919,9 @@ public void testIdcGet10() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用不同大小写的weak Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -850,9 +957,9 @@ public void testIdcGet11() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -888,9 +995,9 @@ public void testIdcGet12() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 Map result = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) @@ -925,9 +1032,9 @@ public void testIdcScan1() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -965,9 +1072,9 @@ public void testIdcScan2() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1005,9 +1112,9 @@ public void testIdcScan3() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1045,9 +1152,9 @@ public void testIdcScan4() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1086,9 +1193,9 @@ public void testIdcScan5() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,使用strong consistency QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1126,9 +1233,9 @@ public void testIdcScan6() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1166,9 +1273,9 @@ public void testIdcScan7() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用非法的ReadConsistency值,应该抛出异常 try { ObReadConsistency.getByName("invalid_consistency"); // 非法的consistency值 @@ -1197,9 +1304,9 @@ public void testIdcScan8() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc(只设置IDC1, IDC2, IDC3,不设置IDC4) - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1238,9 +1345,9 @@ public void testIdcScan9() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 不设置ReadConsistency,使用默认值(应该是strong) QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1278,9 +1385,9 @@ public void testIdcScan10() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用不同大小写的weak QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1319,9 +1426,9 @@ public void testIdcScan11() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1360,9 +1467,9 @@ public void testIdcScan12() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 QueryResultSet res = client.query(TABLE_NAME) .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) @@ -1400,9 +1507,9 @@ public void testIdcBatchGet1() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1440,9 +1547,9 @@ public void testIdcBatchGet2() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1480,9 +1587,9 @@ public void testIdcBatchGet3() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1520,9 +1627,9 @@ public void testIdcBatchGet4() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1561,9 +1668,9 @@ public void testIdcBatchGet5() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,使用strong consistency BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1601,9 +1708,9 @@ public void testIdcBatchGet6() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1641,9 +1748,9 @@ public void testIdcBatchGet7() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用非法的ReadConsistency值,应该抛出异常 try { ObReadConsistency.getByName("invalid_consistency"); // 非法的consistency值 @@ -1672,9 +1779,9 @@ public void testIdcBatchGet8() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc(只设置IDC1, IDC2, IDC3,不设置IDC4) - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1713,9 +1820,9 @@ public void testIdcBatchGet9() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 不设置ReadConsistency,使用默认值(应该是strong) BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1753,9 +1860,9 @@ public void testIdcBatchGet10() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用不同大小写的weak BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1794,9 +1901,9 @@ public void testIdcBatchGet11() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1835,9 +1942,9 @@ public void testIdcBatchGet12() throws Exception { insertData(client, rowkey); Thread.sleep(1000); // 等待数据同步到所有节点 // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 BatchOperation batch = client.batchOperation(TABLE_NAME); Get get = client.get(TABLE_NAME) @@ -1872,9 +1979,9 @@ public void testDmlInsertWithGlobalWeak() throws Exception { client.setCurrentIDC(IDC2); // 设置当前 idc client.init(); // 1. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 2. 执行INSERT操作 String rowkey = getRandomRowkString(); client.insert(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) @@ -1906,9 +2013,9 @@ public void testDmlUpdateWithGlobalWeak() throws Exception { insertData(client, rowkey); Thread.sleep(500); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 执行UPDATE操作 client.update(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) .addMutateRow(row(colVal("c2", "c2_val_updated"))).execute(); @@ -1938,9 +2045,9 @@ public void testDmlDeleteWithGlobalWeak() throws Exception { String rowkey = getRandomRowkString(); insertData(client, rowkey); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 执行DELETE操作 client.delete(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))).execute(); // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 @@ -1967,9 +2074,9 @@ public void testDmlReplaceWithGlobalWeak() throws Exception { client.init(); // 1. 设置 idc String rowkey = getRandomRowkString(); - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 2. 执行REPLACE操作 client.replace(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) .addMutateRow(row(colVal("c2", "c2_val_replaced"))).execute(); @@ -1997,9 +2104,9 @@ public void testDmlInsertOrUpdateWithGlobalWeak() throws Exception { client.init(); // 1. 设置 idc String rowkey = getRandomRowkString(); - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 2. 执行INSERT_OR_UPDATE操作 client.insertOrUpdate(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) .addMutateRow(row(colVal("c2", "c2_val"))).execute(); @@ -2029,9 +2136,9 @@ public void testDmlPutWithGlobalWeak() throws Exception { client.init(); // 1. 设置 idc String rowkey = getRandomRowkString(); - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 2. 执行PUT操作 client.put(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) .addMutateRow(row(colVal("c2", "c2_val_put"))).execute(); @@ -2064,9 +2171,9 @@ public void testDmlIncrementWithGlobalWeak() throws Exception { client.init(); // 1. 设置 idc String rowkey = getRandomRowkString(); - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 2. 执行INCREMENT操作(注意:INCREMENT通常用于数值类型,这里仅测试路由逻辑) // 由于表结构是varchar,这里可能失败,但我们可以先测试路由 try { @@ -2103,9 +2210,9 @@ public void testDmlAppendWithGlobalWeak() throws Exception { String rowkey = getRandomRowkString(); insertData(client, rowkey); // 2. 设置 idc - setZoneIdc(ZONE1, IDC1); - setZoneIdc(ZONE2, IDC2); - setZoneIdc(ZONE3, IDC3); + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 执行APPEND操作 client.append(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) .addMutateRow(row(colVal("c2", "_appended"))).execute(); From 4429e5bce022abdbe5a7e2efc866f46241c84d4e Mon Sep 17 00:00:00 2001 From: Ziyu Shi Date: Thu, 4 Dec 2025 10:30:37 +0800 Subject: [PATCH 06/10] fix set setRpcExecuteTimeout nullpointer (#415) --- .../alipay/oceanbase/rpc/ObTableClient.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java index 3f71128d..74b4cb62 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java +++ b/src/main/java/com/alipay/oceanbase/rpc/ObTableClient.java @@ -904,19 +904,21 @@ public void eraseTableEntry(String tableName) { public void setRpcExecuteTimeout(int rpcExecuteTimeout) { this.properties.put(RPC_EXECUTE_TIMEOUT.getKey(), String.valueOf(rpcExecuteTimeout)); this.rpcExecuteTimeout = rpcExecuteTimeout; - if (tableRoute != null) { - ConcurrentHashMap tableRoster = tableRoute.getTableRoster().getTables(); + if (odpMode) { + ObTable odpTable = tableRoute.getOdpTable(); + if (null != odpTable) { + odpTable.setObTableExecuteTimeout(rpcExecuteTimeout); + } + } else { + TableRoster tableRoster = tableRoute.getTableRoster(); if (null != tableRoster) { - for (ObTable obTable : tableRoster.values()) { - if (obTable != null) { + ConcurrentHashMap addTableMap = tableRoster.getTables(); + for (ObTable obTable : addTableMap.values()) { + if (null != obTable) { obTable.setObTableExecuteTimeout(rpcExecuteTimeout); } } } - ObTable odpTable = tableRoute.getOdpTable(); - if (null != odpTable) { - odpTable.setObTableExecuteTimeout(rpcExecuteTimeout); - } } } From 92b546b5eccaa4c69c18b6a6e6019ec116aff1b0 Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:15:32 +0800 Subject: [PATCH 07/10] fix weak read in batch get (#416) --- .../rpc/mutation/BatchOperation.java | 44 ++++-- .../oceanbase/rpc/ObTableWeakReadTest.java | 126 +++++++++++++++--- 2 files changed, 139 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java index ca02e48e..ad9eb306 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java @@ -54,6 +54,7 @@ public class BatchOperation { boolean isSameType = true; protected ObTableEntityType entityType = ObTableEntityType.KV; protected OHOperationType hbaseOpType = OHOperationType.INVALID; + protected ObReadConsistency readConsistency = null; // BatchOperation 级别的弱读设置 /* * default constructor @@ -63,6 +64,7 @@ public BatchOperation() { client = null; withResult = false; operations = new ArrayList<>(); + readConsistency = null; } /* @@ -188,6 +190,25 @@ public void setEntityType(ObTableEntityType entityType) { this.entityType = entityType; } + /** + * Set read consistency level for batch operation. + * This setting will override the readConsistency settings on individual Get operations. + * @param readConsistency read consistency level + * @return this + */ + public BatchOperation setReadConsistency(ObReadConsistency readConsistency) { + this.readConsistency = readConsistency; + return this; + } + + /** + * Get read consistency level for batch operation. + * @return read consistency level + */ + public ObReadConsistency getReadConsistency() { + return readConsistency; + } + public void setServerCanRetry(boolean canRetry) { this.serverCanRetry = canRetry; } @@ -317,13 +338,6 @@ private BatchOperationResult executeWithNormalBatchOp() throws Exception { return new BatchOperationResult(batchOps.executeWithResult()); } - private boolean checkReadConsistency(ObTableClient obTableClient, ObReadConsistency readConsistency) throws IllegalArgumentException { - // 如果没有设置语句级别的 readConsistency(null),使用 TableRoute 上的 consistencyLevel - if (readConsistency == null) { - return obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; - } - return readConsistency == ObReadConsistency.WEAK; - } private BatchOperationResult executeWithLSBatchOp() throws Exception { if (tableName == null || tableName.isEmpty()) { @@ -369,11 +383,23 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { if (get.getRowKey() == null) { throw new IllegalArgumentException("RowKey is null in Get operation"); } - isWeakRead = checkReadConsistency(obTableClient, get.getReadConsistency()); + // BatchOperation 级别的 readConsistency 优先,忽略 Get 上的设置 + if (readConsistency != null) { + isWeakRead = (readConsistency == ObReadConsistency.WEAK); + } else { + // 如果 BatchOperation 没有设置,使用 TableRoute 上的全局设置 + isWeakRead = obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; + } batchOps.addOperation(get); } else if (operation instanceof TableQuery) { TableQuery query = (TableQuery) operation; - isWeakRead = checkReadConsistency(obTableClient, query.getReadConsistency()); + // BatchOperation 级别的 readConsistency 优先,忽略 TableQuery 上的设置 + if (readConsistency != null) { + isWeakRead = (readConsistency == ObReadConsistency.WEAK); + } else { + // 如果 BatchOperation 没有设置,使用 TableRoute 上的全局设置 + isWeakRead = obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; + } batchOps.addOperation(query); } else if (operation instanceof QueryAndMutate) { QueryAndMutate qm = (QueryAndMutate) operation; diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java index 881adbeb..1e386a38 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java @@ -48,16 +48,18 @@ class SqlAuditResult { public String svrIp; public int svrPort; public int tabletId; + public int consistency_level; - public SqlAuditResult(String svrIp, int svrPort, int tabletId) { + public SqlAuditResult(String svrIp, int svrPort, int tabletId, int consistency_level) { this.svrIp = svrIp; this.svrPort = svrPort; this.tabletId = tabletId; + this.consistency_level = consistency_level; } @Override public String toString() { - return "SqlAuditResult{" + "svrIp='" + svrIp + '\'' + ", svrPort=" + svrPort + ", tabletId=" + tabletId + '}'; + return "SqlAuditResult{" + "svrIp='" + svrIp + '\'' + ", svrPort=" + svrPort + ", tabletId=" + tabletId + ", consistency_level=" + consistency_level + '}'; } } @@ -413,6 +415,38 @@ private int extractTabletId(String querySql) { } } + private int extractConsistencyLevel(String querySql) { + // 查找 consistency_level: 的模式 + String pattern = "consistency_level:"; + int startIndex = querySql.indexOf(pattern); + if (startIndex == -1) { + return -1; // 如果找不到,返回 -1 + } + // 找到 : 后面的数字开始位置 + int levelStartIndex = startIndex + pattern.length(); + // 跳过可能的空格 + while (levelStartIndex < querySql.length() && Character.isWhitespace(querySql.charAt(levelStartIndex))) { + levelStartIndex++; + } + // 找到数字结束位置(遇到 , 或 } 或空格) + int levelEndIndex = levelStartIndex; + while (levelEndIndex < querySql.length()) { + char c = querySql.charAt(levelEndIndex); + if (c == ',' || c == '}' || c == ' ') { + break; + } + levelEndIndex++; + } + // 提取数字字符串 + String consistencyLevelStr = querySql.substring(levelStartIndex, levelEndIndex).trim(); + try { + return Integer.parseInt(consistencyLevelStr); + } catch (NumberFormatException e) { + debugPrint("Failed to parse consistency_level from: %s", consistencyLevelStr); + return -1; + } + } + private static int getTenantId(Connection connection) throws Exception { PreparedStatement statement = connection.prepareStatement(GET_TENANT_ID_SQL); statement.setString(1, TENANT_NAME); @@ -444,7 +478,8 @@ private SqlAuditResult getServerBySqlAudit(String rowkey, String stmtType) throw int svrPort = resultSet.getInt("svr_port"); String querySql = resultSet.getString("query_sql"); int tabletId = extractTabletId(querySql); - sqlAuditResult = new SqlAuditResult(svrIp, svrPort, tabletId); + int consistencyLevel = extractConsistencyLevel(querySql); + sqlAuditResult = new SqlAuditResult(svrIp, svrPort, tabletId, consistencyLevel); debugPrint("querySql: %s", querySql); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); } @@ -1511,19 +1546,23 @@ public void testIdcBatchGet1() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 - BatchOperation batch = client.batchOperation(TABLE_NAME); - Get get = client.get(TABLE_NAME) + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.WEAK); // 设置弱一致性读 + Get get1 = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); - batch.addOperation(get); + Get get2 = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey + "2"))) + .select("c2"); + batch.addOperation(get1, get2); BatchOperationResult res = batch.execute(); Assert.assertNotNull(res); - Assert.assertEquals(1, res.getResults().size()); + Assert.assertEquals(2, res.getResults().size()); Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1533,6 +1572,49 @@ public void testIdcBatchGet1() throws Exception { Assert.assertEquals(IDC2, readReplica.getIdc()); } + /* + * 测试场景:用户正常使用场景,使用batch get接口进行指定IDC读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testIdcBatchGet1_1() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get1 = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .select("c2"); + Get get2 = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey + "2"))) + .select("c2"); + batch.addOperation(get1, get2); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(2, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + /* * 测试场景:未设置当前IDC进行弱读 * 测试预期:发到任意follower上进行弱读 @@ -1551,10 +1633,10 @@ public void testIdcBatchGet2() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.WEAK); // 设置弱一致性读 Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1631,10 +1713,10 @@ public void testIdcBatchGet4() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.WEAK); // 设置弱一致性读 Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1672,10 +1754,10 @@ public void testIdcBatchGet5() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,使用strong consistency - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.STRONG); // 设置强一致性读 Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.STRONG) // 设置强一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1712,10 +1794,10 @@ public void testIdcBatchGet6() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.WEAK); // 设置弱一致性读 Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1783,10 +1865,10 @@ public void testIdcBatchGet8() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据 - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.WEAK); // 设置弱一致性读 Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.WEAK) .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1864,10 +1946,10 @@ public void testIdcBatchGet10() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 使用不同大小写的weak - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.WEAK); // 设置弱一致性读 Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.WEAK) // 大写 .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); @@ -1946,10 +2028,10 @@ public void testIdcBatchGet12() throws Exception { setZoneRegionIdc(ZONE2, REGION2, IDC2); setZoneRegionIdc(ZONE3, REGION3, IDC3); // 3. 获取数据,语句级别设置为strong,应该覆盖全局的weak设置 - BatchOperation batch = client.batchOperation(TABLE_NAME); + BatchOperation batch = client.batchOperation(TABLE_NAME) + .setReadConsistency(ObReadConsistency.STRONG); // 语句级别设置为strong,应该覆盖全局的weak Get get = client.get(TABLE_NAME) .setRowKey(row(colVal("c1", rowkey))) - .setReadConsistency(ObReadConsistency.STRONG) // 语句级别设置为strong,应该覆盖全局的weak .select("c2"); batch.addOperation(get); BatchOperationResult res = batch.execute(); From 49f04c40810268a186c765c514b771bfc4fa0e12 Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:38:54 +0800 Subject: [PATCH 08/10] support weak in old interface (#417) --- .../rpc/mutation/BatchOperation.java | 21 +- .../rpc/table/ObTableClientBatchOpsImpl.java | 4 + .../oceanbase/rpc/ObTableWeakReadTest.java | 629 +++++++++++++++++- 3 files changed, 636 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java index ad9eb306..9feb00f2 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java @@ -355,6 +355,13 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { batchOps.setServerCanRetry(serverCanRetry); batchOps.setNeedTabletId(needTabletId); batchOps.setHbaseOpType(hbaseOpType); + if (readConsistency != null) { + isWeakRead = (readConsistency == ObReadConsistency.WEAK); + } else { + // 如果 BatchOperation 没有设置,使用 TableRoute 上的全局设置 + isWeakRead = obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; + } + batchOps.setIsWeakRead(isWeakRead); for (Object operation : operations) { if (operation instanceof CheckAndInsUp) { checkAndInsUpCnt++; @@ -383,23 +390,9 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { if (get.getRowKey() == null) { throw new IllegalArgumentException("RowKey is null in Get operation"); } - // BatchOperation 级别的 readConsistency 优先,忽略 Get 上的设置 - if (readConsistency != null) { - isWeakRead = (readConsistency == ObReadConsistency.WEAK); - } else { - // 如果 BatchOperation 没有设置,使用 TableRoute 上的全局设置 - isWeakRead = obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; - } batchOps.addOperation(get); } else if (operation instanceof TableQuery) { TableQuery query = (TableQuery) operation; - // BatchOperation 级别的 readConsistency 优先,忽略 TableQuery 上的设置 - if (readConsistency != null) { - isWeakRead = (readConsistency == ObReadConsistency.WEAK); - } else { - // 如果 BatchOperation 没有设置,使用 TableRoute 上的全局设置 - isWeakRead = obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; - } batchOps.addOperation(query); } else if (operation instanceof QueryAndMutate) { QueryAndMutate qm = (QueryAndMutate) operation; diff --git a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java index 1e2e37ed..593e36f5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java +++ b/src/main/java/com/alipay/oceanbase/rpc/table/ObTableClientBatchOpsImpl.java @@ -590,6 +590,10 @@ public ObTableBatchOperationResult executeInternal() throws Exception { if (tableName == null || tableName.isEmpty()) { throw new IllegalArgumentException("table name is null"); } + if (batchOperation.isReadOnly()) { + setIsWeakRead(obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK); + } + long start = System.currentTimeMillis(); List operations = batchOperation.getTableOperations(); ObTableOperationResult[] obTableOperationResults = returnOneResult ? new ObTableOperationResult[1] diff --git a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java index 1e386a38..faf7077f 100644 --- a/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java +++ b/src/test/java/com/alipay/oceanbase/rpc/ObTableWeakReadTest.java @@ -31,6 +31,7 @@ import com.alipay.oceanbase.rpc.mutation.result.BatchOperationResult; import com.alipay.oceanbase.rpc.protocol.payload.impl.execute.ObReadConsistency; import com.alipay.oceanbase.rpc.stream.QueryResultSet; +import com.alipay.oceanbase.rpc.table.api.TableBatchOps; import org.junit.After; import org.junit.Assert; @@ -227,10 +228,28 @@ public class ObTableWeakReadTest { * 创建新的测试客户端 */ private static ObTableClient newTestClient() throws Exception { + if (USE_ODP) { + ObTableClient obTableClient = new ObTableClient(); + obTableClient.setOdpMode(true); + obTableClient.setFullUserName(FULL_USER_NAME); + obTableClient.setOdpAddr(ODP_IP); + obTableClient.setOdpPort(ODP_RPC_PORT); + obTableClient.setDatabase(ODP_DATABASE); + obTableClient.setPassword(PASSWORD); + return obTableClient; + } else { + return newTestClientWithParamURL(PARAM_URL); + } + } + + /** + * 创建新的测试客户端,使用指定的paramURL + */ + private static ObTableClient newTestClientWithParamURL(String paramURL) throws Exception { ObTableClient obTableClient = new ObTableClient(); if (!USE_ODP) { obTableClient.setFullUserName(FULL_USER_NAME); - obTableClient.setParamURL(PARAM_URL); + obTableClient.setParamURL(paramURL); obTableClient.setPassword(PASSWORD); obTableClient.setSysUserName(PROXY_SYS_USER_NAME); obTableClient.setSysPassword(PROXY_SYS_USER_PASSWORD); @@ -600,6 +619,7 @@ public void testIdcGet1() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -638,6 +658,7 @@ public void testIdcGet1_1() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -645,7 +666,7 @@ public void testIdcGet1_1() throws Exception { ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); debugPrint("readReplica: %s", readReplica.toString()); Assert.assertTrue(readReplica.isFollower()); - Assert.assertEquals(IDC2, readReplica.getIdc()); + Assert.assertEquals(REGION1, readReplica.getRegion()); } /* @@ -676,6 +697,7 @@ public void testIdcGet2() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -750,6 +772,7 @@ public void testIdcGet4() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -825,6 +848,7 @@ public void testIdcGet6() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1006,6 +1030,7 @@ public void testIdcGet11() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1084,6 +1109,7 @@ public void testIdcScan1() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1124,6 +1150,7 @@ public void testIdcScan2() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1204,6 +1231,7 @@ public void testIdcScan4() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1285,6 +1313,7 @@ public void testIdcScan6() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1356,6 +1385,7 @@ public void testIdcScan8() throws Exception { // 4. 查询 sql audit SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1437,6 +1467,7 @@ public void testIdcScan10() throws Exception { // 4. 查询 sql audit SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1478,6 +1509,7 @@ public void testIdcScan11() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1615,6 +1647,51 @@ public void testIdcBatchGet1_1() throws Exception { Assert.assertTrue(readReplica.isLeader()); } + /* + * 测试场景:没有设置全局弱读,即使 Get 设置了弱读,BatchOperation 没有设置,走强读 + * 测试预期:走强读,发到leader副本上进行读取 + */ + @Test + public void testIdcBatchGet1_2() throws Exception { + ObTableClient client = newTestClient(); + client.setCurrentIDC(IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + BatchOperation batch = client.batchOperation(TABLE_NAME); + Get get1 = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey))) + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 + .select("c2"); + Get get2 = client.get(TABLE_NAME) + .setRowKey(row(colVal("c1", rowkey + "2"))) + .setReadConsistency(ObReadConsistency.WEAK) // 设置弱一致性读 + .select("c2"); + batch.addOperation(get1, get2); + BatchOperationResult res = batch.execute(); + Assert.assertNotNull(res); + Assert.assertEquals(2, res.getResults().size()); + Assert.assertEquals("c2_val", res.get(0).getOperationRow().get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + /* * 测试场景:未设置当前IDC进行弱读 * 测试预期:发到任意follower上进行弱读 @@ -1726,6 +1803,7 @@ public void testIdcBatchGet4() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1878,6 +1956,7 @@ public void testIdcBatchGet8() throws Exception { // 4. 查询 sql audit SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -1959,6 +2038,7 @@ public void testIdcBatchGet10() throws Exception { // 4. 查询 sql audit SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2000,6 +2080,7 @@ public void testIdcBatchGet11() throws Exception { // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2071,6 +2152,7 @@ public void testDmlInsertWithGlobalWeak() throws Exception { // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, INSERT_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 4. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2104,6 +2186,7 @@ public void testDmlUpdateWithGlobalWeak() throws Exception { // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, UPDATE_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2135,6 +2218,7 @@ public void testDmlDeleteWithGlobalWeak() throws Exception { // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, DELETE_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2165,6 +2249,7 @@ public void testDmlReplaceWithGlobalWeak() throws Exception { // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, REPLACE_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 4. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2195,6 +2280,7 @@ public void testDmlInsertOrUpdateWithGlobalWeak() throws Exception { // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, INSERT_OR_UPDATE_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 4. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2227,6 +2313,7 @@ public void testDmlPutWithGlobalWeak() throws Exception { // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, PUT_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 4. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2261,9 +2348,10 @@ public void testDmlIncrementWithGlobalWeak() throws Exception { try { client.increment(TABLE_NAME).setRowKey(row(colVal("c1", rowkey))) .addMutateRow(row(colVal("c2", "1"))).execute(); - // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 + // 3. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, INCREMENT_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 4. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2301,6 +2389,7 @@ public void testDmlAppendWithGlobalWeak() throws Exception { // 4. 查询 sql audit,确定写请求发到哪个节点和分区上 SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, APPEND_STMT_TYPE); debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); // 5. 查询分区的位置信息 PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); debugPrint("partitionLocation: %s", partitionLocation.toString()); @@ -2309,5 +2398,537 @@ public void testDmlAppendWithGlobalWeak() throws Exception { debugPrint("writeReplica: %s", writeReplica.toString()); Assert.assertTrue(writeReplica.isLeader()); } - + + /* + * 测试场景:老接口只能使用全局弱读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcGet1_1() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME, row(colVal("c1", rowkey)), new String[] { "c2" }); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:老接口只能使用全局弱读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcGet1_2() throws Exception { + ObTableClient client = newTestClient(); + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME, row(colVal("c1", rowkey)), new String[] { "c2" }); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:在paramUrl中设置弱读核路由策略 + * 测试预期:走弱读,发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcGet2_1() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weak&route_policy=follower_first"); + setIdc(client, IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME, row(colVal("c1", rowkey)), new String[] { "c2" }); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:在paramUrl中设置弱读核路由策略,不设置IDC + * 测试预期:走弱读 + */ + @Test + public void testOldInterfaceIdcGet2_2() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weak&route_policy=follower_first"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME, row(colVal("c1", rowkey)), new String[] { "c2" }); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:read_consistency和route_policy 大小写不敏感 + * 测试预期:走弱读 + */ + @Test + public void testOldInterfaceIdcGet2_3() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weaK&route_policy=follower_firsT"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + Map result = client.get(TABLE_NAME, row(colVal("c1", rowkey)), new String[] { "c2" }); + debugPrint("c2_val: %s", result.get("c2")); + Assert.assertEquals("c2_val", result.get("c2")); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:老接口只能使用全局弱读 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcBatchGet1_1() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + TableBatchOps batchOps = client.batch(TABLE_NAME); + batchOps.get(rowkey, new String[] { "c2" }); + batchOps.get(rowkey + "2", new String[] { "c2" }); + List results = batchOps.execute(); + Assert.assertEquals(2, results.size()); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:老接口只能使用全局弱读,执行scan操作 + * 测试预期:发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcScan1_1() throws Exception { + ObTableClient client = newTestClient(); + client.setReadConsistency(ObReadConsistency.WEAK); // 设置全局的read consistency level为weak + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .select("c2") + .execute(); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:老接口只能使用全局弱读,不设置全局弱读时走强读 + * 测试预期:走强读,发到leader副本上进行读取 + */ + @Test + public void testOldInterfaceIdcBatchGet1_2() throws Exception { + ObTableClient client = newTestClient(); + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + TableBatchOps batchOps = client.batch(TABLE_NAME); + batchOps.get(rowkey, new String[] { "c2" }); + batchOps.get(rowkey + "2", new String[] { "c2" }); + List results = batchOps.execute(); + Assert.assertEquals(2, results.size()); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:在paramUrl中设置弱读和路由策略,执行batch get操作 + * 测试预期:走弱读,发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcBatchGet2_1() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weak&route_policy=follower_first"); + setIdc(client, IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + TableBatchOps batchOps = client.batch(TABLE_NAME); + batchOps.get(rowkey, new String[] { "c2" }); + batchOps.get(rowkey + "2", new String[] { "c2" }); + List results = batchOps.execute(); + Assert.assertEquals(2, results.size()); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:在paramUrl中设置弱读和路由策略,不设置IDC,执行batch get操作 + * 测试预期:走弱读 + */ + @Test + public void testOldInterfaceIdcBatchGet2_2() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weak&route_policy=follower_first"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + TableBatchOps batchOps = client.batch(TABLE_NAME); + batchOps.get(rowkey, new String[] { "c2" }); + batchOps.get(rowkey + "2", new String[] { "c2" }); + List results = batchOps.execute(); + Assert.assertEquals(2, results.size()); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:read_consistency和route_policy 大小写不敏感,执行batch get操作 + * 测试预期:走弱读 + */ + @Test + public void testOldInterfaceIdcBatchGet2_3() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weaK&route_policy=follower_firsT"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + TableBatchOps batchOps = client.batch(TABLE_NAME); + batchOps.get(rowkey, new String[] { "c2" }); + batchOps.get(rowkey + "2", new String[] { "c2" }); + List results = batchOps.execute(); + Assert.assertEquals(2, results.size()); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, BATCH_GET_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:老接口只能使用全局弱读,不设置全局弱读时走强读 + * 测试预期:走强读,发到leader副本上进行读取 + */ + @Test + public void testOldInterfaceIdcScan1_2() throws Exception { + ObTableClient client = newTestClient(); + setIdc(client, IDC2); // 设置当前 idc + setRoutePolicy(client, "follower_first"); // 设置路由策略 + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .select("c2") + .execute(); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.STRONG.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isLeader()); + } + + /* + * 测试场景:在paramUrl中设置弱读和路由策略,执行scan操作 + * 测试预期:走弱读,发到对应的IDC上进行读取 + */ + @Test + public void testOldInterfaceIdcScan2_1() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weak&route_policy=follower_first"); + setIdc(client, IDC2); // 设置当前 idc + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .select("c2") + .execute(); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertEquals(IDC2, readReplica.getIdc()); + } + + /* + * 测试场景:在paramUrl中设置弱读和路由策略,不设置IDC,执行scan操作 + * 测试预期:走弱读 + */ + @Test + public void testOldInterfaceIdcScan2_2() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weak&route_policy=follower_first"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .select("c2") + .execute(); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } + + /* + * 测试场景:read_consistency和route_policy 大小写不敏感,执行scan操作 + * 测试预期:走弱读 + */ + @Test + public void testOldInterfaceIdcScan2_3() throws Exception { + ObTableClient client = newTestClientWithParamURL(PARAM_URL + "&read_consistency=weaK&route_policy=follower_firsT"); + client.init(); + // 1. 准备数据 + String rowkey = getRandomRowkString(); + insertData(client, rowkey); + Thread.sleep(1000); // 等待数据同步到所有节点 + // 2. 设置 idc + setZoneRegionIdc(ZONE1, REGION1, IDC1); + setZoneRegionIdc(ZONE2, REGION2, IDC2); + setZoneRegionIdc(ZONE3, REGION3, IDC3); + // 3. 获取数据 + client.query(TABLE_NAME) + .addScanRange(new Object[] { rowkey }, new Object[] { rowkey }) + .setScanRangeColumns("c1") + .select("c2") + .execute(); + // 4. 查询 sql audit,确定读请求发到哪个节点和分区上 + SqlAuditResult sqlAuditResult = getServerBySqlAudit(rowkey, SCAN_STMT_TYPE); + debugPrint("sqlAuditResult: %s", sqlAuditResult.toString()); + Assert.assertEquals(ObReadConsistency.WEAK.getValue(), sqlAuditResult.consistency_level); + // 5. 查询分区的位置信息 + PartitionLocation partitionLocation = getPartitionLocation(sqlAuditResult.tabletId); + debugPrint("partitionLocation: %s", partitionLocation.toString()); + // 6. 校验 + ReplicaLocation readReplica = partitionLocation.getReplicaBySvrAddr(sqlAuditResult.svrIp, sqlAuditResult.svrPort); + debugPrint("readReplica: %s", readReplica.toString()); + Assert.assertTrue(readReplica.isFollower()); + } } From 9466ae75ceedf6b79cf015209ef86a691c094982 Mon Sep 17 00:00:00 2001 From: vanson <43193589+WeiXinChan@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:31:12 +0800 Subject: [PATCH 09/10] fix weak read in BatchOperation (#418) --- .../java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java index 9feb00f2..6d8420b1 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java +++ b/src/main/java/com/alipay/oceanbase/rpc/mutation/BatchOperation.java @@ -361,7 +361,6 @@ private BatchOperationResult executeWithLSBatchOp() throws Exception { // 如果 BatchOperation 没有设置,使用 TableRoute 上的全局设置 isWeakRead = obTableClient.getTableRoute().getReadConsistency() == ObReadConsistency.WEAK; } - batchOps.setIsWeakRead(isWeakRead); for (Object operation : operations) { if (operation instanceof CheckAndInsUp) { checkAndInsUpCnt++; From 4939c4d14aaf4fd92ced789f33c2bcf1787b2583 Mon Sep 17 00:00:00 2001 From: maochongxin Date: Thu, 11 Dec 2025 14:13:08 +0800 Subject: [PATCH 10/10] add get_optimized flag for obtablequery --- .../payload/impl/execute/query/ObTableQuery.java | 4 ++++ .../payload/impl/execute/query/ObTableQueryFlag.java | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQuery.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQuery.java index f817d322..7dfa14b5 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQuery.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQuery.java @@ -618,4 +618,8 @@ public void setFlag(ObTableQueryFlag flag) { public void setHotOnly(boolean hotOnly) { this.flag.setHotOnly(hotOnly); } + + public void setGetOptimized(boolean getOptimized) { + this.flag.setGetOptimized(getOptimized); + } } diff --git a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryFlag.java b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryFlag.java index 4209ab44..4008a23b 100644 --- a/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryFlag.java +++ b/src/main/java/com/alipay/oceanbase/rpc/protocol/payload/impl/execute/query/ObTableQueryFlag.java @@ -19,6 +19,7 @@ public class ObTableQueryFlag { private static final int HOT_ONLY = 1 << 0; + private static final int GET_OPTIMIZED = 1 << 1; private long value = 0; @@ -43,4 +44,14 @@ public void setHotOnly(boolean hotOnly) { value = value | HOT_ONLY; } } + + public boolean isGetOptimized() { + return (value & GET_OPTIMIZED) != 0; + } + + public void setGetOptimized(boolean getOptimized) { + if (getOptimized) { + value = value | GET_OPTIMIZED; + } + } };