diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index d142e8dfb..e5d0d7575 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -6,7 +6,7 @@ com.aerospike aerospike-parent - 8.1.1 + 8.1.2 aerospike-benchmarks jar diff --git a/client/pom.xml b/client/pom.xml index f575c3e25..95525ba34 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -6,7 +6,7 @@ com.aerospike aerospike-parent - 8.1.1 + 8.1.2 aerospike-client-jdk21 jar @@ -129,6 +129,7 @@ com/aerospike/client/listener/* com/aerospike/client/command/ParticleType.java com/aerospike/client/exp/* + com/aerospike/client/metrics/* com/aerospike/client/operation/* com/aerospike/client/policy/* com/aerospike/client/task/* diff --git a/client/src/com/aerospike/client/AerospikeClient.java b/client/src/com/aerospike/client/AerospikeClient.java index f5ffee2c7..df7c8dbd2 100644 --- a/client/src/com/aerospike/client/AerospikeClient.java +++ b/client/src/com/aerospike/client/AerospikeClient.java @@ -1786,6 +1786,9 @@ public final Record[] get(BatchPolicy policy, Key[] keys, String... binNames) policy = batchPolicyDefault; } + int readAttr = (binNames == null || binNames.length == 0)? + Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + Record[] records = new Record[keys.length]; try { @@ -1802,7 +1805,7 @@ public final Record[] get(BatchPolicy policy, Key[] keys, String... binNames) } else { commands[count++] = new Batch.GetArrayCommand( - cluster, bn, policy, keys, binNames, null, records, Command.INFO1_READ, false, status); + cluster, bn, policy, keys, binNames, null, records, readAttr, false, status); } } BatchExecutor.execute(cluster, policy, commands, status); @@ -1844,6 +1847,9 @@ public final void get(EventLoop eventLoop, RecordArrayListener listener, BatchPo policy = batchPolicyDefault; } + int readAttr = (binNames == null || binNames.length == 0)? + Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + Record[] records = new Record[keys.length]; AsyncBatchExecutor.GetArray executor = new AsyncBatchExecutor.GetArray( eventLoop, cluster, listener, keys, records); @@ -1859,7 +1865,7 @@ public final void get(EventLoop eventLoop, RecordArrayListener listener, BatchPo } else { commands[count++] = new AsyncBatch.GetArrayCommand( - executor, bn, policy, keys, binNames, null, records, Command.INFO1_READ, false); + executor, bn, policy, keys, binNames, null, records, readAttr, false); } } executor.execute(commands); @@ -1896,6 +1902,9 @@ public final void get(EventLoop eventLoop, RecordSequenceListener listener, Batc policy = batchPolicyDefault; } + int readAttr = (binNames == null || binNames.length == 0)? + Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ; + AsyncBatchExecutor.GetSequence executor = new AsyncBatchExecutor.GetSequence(eventLoop, cluster, listener); List bns = BatchNodeList.generate(cluster, policy, keys, null, false, executor); AsyncCommand[] commands = new AsyncCommand[bns.size()]; @@ -1909,7 +1918,7 @@ public final void get(EventLoop eventLoop, RecordSequenceListener listener, Batc } else { commands[count++] = new AsyncBatch.GetSequenceCommand( - executor, bn, policy, keys, binNames, null, listener, Command.INFO1_READ, false); + executor, bn, policy, keys, binNames, null, listener, readAttr, false); } } executor.execute(commands); @@ -4461,21 +4470,7 @@ public void onFailure(AerospikeException ae) { } private static int parseIndexErrorCode(String response) { - int code = 0; - - try { - String[] list = response.split(":"); - - if (list.length >= 2 && list[0].equals("FAIL")) { - code = Integer.parseInt(list[1]); - } - } - catch (Throwable e) { - } - - if (code == 0) { - code = ResultCode.SERVER_ERROR; - } - return code; + Info.Error error = new Info.Error(response); + return (error.code == 0)? ResultCode.SERVER_ERROR : error.code; } } diff --git a/client/src/com/aerospike/client/Info.java b/client/src/com/aerospike/client/Info.java index 402ed015c..c9d4793b1 100644 --- a/client/src/com/aerospike/client/Info.java +++ b/client/src/com/aerospike/client/Info.java @@ -319,30 +319,15 @@ public static int parseResultCode(String response) { return ResultCode.OK; } - // Error format: ERROR|FAIL[:][:] - try { - String[] list = response.split(":"); - String s = list[0]; - - if (s.regionMatches(true, 0, "FAIL", 0, 4) || - s.regionMatches(true, 0, "ERROR", 0, 5)) { + Info.Error error = new Info.Error(response); - if (list.length > 1) { - s = list[1].trim(); - - if (! s.isEmpty()) { - return Integer.parseInt(s); - } - } - return ResultCode.SERVER_ERROR; - } - throw new AerospikeException("Unrecognized info response: " + response); - } - catch (AerospikeException ae) { - throw ae; + if (error.code >= 0) { + // Server errors return error code. + return error.code; } - catch (Throwable t) { - throw new AerospikeException("Unrecognized info response: " + response, t); + else { + // Client errors result in a exception. + throw new AerospikeException(error.code, "Unrecognized info response: " + response); } } @@ -828,4 +813,61 @@ public String getStringBase64() { return Buffer.utf8ToString(bytes, 0, bytes.length); } } + + /** + * Info command error response. + */ + public static class Error { + public final int code; + public final String message; + + /** + * Parse info command response into code and message. + * If the response is not a recognized error format, the code is set to + * {@link ResultCode#CLIENT_ERROR} and the message is set to the full + * response string. + */ + public Error(String response) { + // Error format: ERROR|FAIL[:][:] + int rc = ResultCode.CLIENT_ERROR; + String msg = response; + + try { + String[] list = response.split(":"); + String s = list[0]; + + if (s.regionMatches(true, 0, "FAIL", 0, 4) || + s.regionMatches(true, 0, "ERROR", 0, 5)) { + + if (list.length >= 3) { + msg = list[2].trim(); + s = list[1].trim(); + + if (! s.isEmpty()) { + rc = Integer.parseInt(s); + } + } + else if (list.length == 2) { + s = list[1].trim(); + + if (! s.isEmpty()) { + try { + rc = Integer.parseInt(s); + } + catch (Throwable t) { + // Some error strings omit the code and just have a message. + msg = s; + } + } + } + } + } + catch (Throwable t) { + } + finally { + this.code = rc; + this.message = msg; + } + } + } } diff --git a/client/src/com/aerospike/client/async/AsyncBatch.java b/client/src/com/aerospike/client/async/AsyncBatch.java index 5893e06ae..22d4fecf6 100644 --- a/client/src/com/aerospike/client/async/AsyncBatch.java +++ b/client/src/com/aerospike/client/async/AsyncBatch.java @@ -16,7 +16,6 @@ */ package com.aerospike.client.async; -import java.util.ArrayList; import java.util.List; import com.aerospike.client.AerospikeClient; diff --git a/client/src/com/aerospike/client/cluster/Connection.java b/client/src/com/aerospike/client/cluster/Connection.java index 73a36bdad..276214ffa 100644 --- a/client/src/com/aerospike/client/cluster/Connection.java +++ b/client/src/com/aerospike/client/cluster/Connection.java @@ -327,6 +327,8 @@ public void close() { } public static final class ReadTimeout extends RuntimeException { + private static final long serialVersionUID = 1L; + public final byte[] buffer; public final int offset; public final int length; diff --git a/client/src/com/aerospike/client/command/BatchAttr.java b/client/src/com/aerospike/client/command/BatchAttr.java index 487a742d0..7f063537e 100644 --- a/client/src/com/aerospike/client/command/BatchAttr.java +++ b/client/src/com/aerospike/client/command/BatchAttr.java @@ -48,7 +48,7 @@ public BatchAttr(Policy policy, int rattr) { public BatchAttr(Policy policy, int rattr, Operation[] ops) { setRead(policy); - this.readAttr |= rattr; + this.readAttr = rattr; if (ops != null) { adjustRead(ops); diff --git a/client/src/com/aerospike/client/command/BatchExecutor.java b/client/src/com/aerospike/client/command/BatchExecutor.java index 704e32ac0..dbd5f9f9d 100644 --- a/client/src/com/aerospike/client/command/BatchExecutor.java +++ b/client/src/com/aerospike/client/command/BatchExecutor.java @@ -18,9 +18,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import com.aerospike.client.AerospikeException; import com.aerospike.client.cluster.Cluster; diff --git a/client/src/com/aerospike/client/command/Command.java b/client/src/com/aerospike/client/command/Command.java index efda4be76..56130f26c 100644 --- a/client/src/com/aerospike/client/command/Command.java +++ b/client/src/com/aerospike/client/command/Command.java @@ -241,7 +241,17 @@ public final void setExists(Policy policy, Key key) { end(); } - private final void setRead(Policy policy, Key key) { + public final void setRead(Policy policy, Key key, String[] binNames) { + int readAttr = Command.INFO1_READ; + int opCount = 0; + + if (binNames != null && binNames.length > 0) { + opCount = binNames.length; + } + else { + readAttr |= Command.INFO1_GET_ALL; + } + begin(); int fieldCount = estimateKeySize(policy, key); @@ -249,45 +259,27 @@ private final void setRead(Policy policy, Key key) { dataOffset += policy.filterExp.size(); fieldCount++; } + + if (opCount != 0) { + for (String binName : binNames) { + estimateOperationSize(binName); + } + } + sizeBuffer(); - writeHeaderRead(policy, serverTimeout, Command.INFO1_READ | Command.INFO1_GET_ALL, 0, 0, fieldCount, 0); + writeHeaderRead(policy, serverTimeout, readAttr, 0, 0, fieldCount, opCount); writeKey(policy, key); if (policy.filterExp != null) { policy.filterExp.write(this); } - end(); - } - - public final void setRead(Policy policy, Key key, String[] binNames) { - if (binNames != null) { - begin(); - int fieldCount = estimateKeySize(policy, key); - - if (policy.filterExp != null) { - dataOffset += policy.filterExp.size(); - fieldCount++; - } - - for (String binName : binNames) { - estimateOperationSize(binName); - } - sizeBuffer(); - writeHeaderRead(policy, serverTimeout, Command.INFO1_READ, 0, 0, fieldCount, binNames.length); - writeKey(policy, key); - - if (policy.filterExp != null) { - policy.filterExp.write(this); - } + if (opCount != 0) { for (String binName : binNames) { writeOperation(binName, Operation.Type.READ); } - end(); - } - else { - setRead(policy, key); } + end(); } public final void setRead(Policy policy, BatchRead br) { @@ -851,7 +843,13 @@ public final void setBatchOperate( } if (br.binNames != null) { - writeBatchBinNames(key, br.binNames, attr, attr.filterExp); + if (br.binNames.length > 0) { + writeBatchBinNames(key, br.binNames, attr, attr.filterExp); + } + else { + attr.adjustRead(true); + writeBatchRead(key, attr, attr.filterExp, 0); + } } else if (br.ops != null) { attr.adjustRead(br.ops); @@ -1330,9 +1328,8 @@ public final void setScan( } // Clusters that support partition queries also support not sending partition done messages. - int infoAttr = cluster.hasPartitionQuery? Command.INFO3_PARTITION_DONE : 0; int operationCount = (binNames == null)? 0 : binNames.length; - writeHeaderRead(policy, totalTimeout, readAttr, 0, infoAttr, fieldCount, operationCount); + writeHeaderRead(policy, totalTimeout, readAttr, 0, Command.INFO3_PARTITION_DONE, fieldCount, operationCount); if (namespace != null) { writeField(namespace, FieldType.NAMESPACE); @@ -1582,7 +1579,7 @@ else if (qp.expectedDuration == QueryDuration.LONG_RELAX_AP) { writeAttr |= Command.INFO2_RELAX_AP_LONG_QUERY; } - int infoAttr = isNew? Command.INFO3_PARTITION_DONE : 0; + int infoAttr = (isNew || filter == null)? Command.INFO3_PARTITION_DONE : 0; writeHeaderRead(policy, totalTimeout, readAttr, writeAttr, infoAttr, fieldCount, operationCount); } diff --git a/client/src/com/aerospike/client/metrics/LatencyBuckets.java b/client/src/com/aerospike/client/metrics/LatencyBuckets.java index db61b2089..ca1b9df3e 100644 --- a/client/src/com/aerospike/client/metrics/LatencyBuckets.java +++ b/client/src/com/aerospike/client/metrics/LatencyBuckets.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 Aerospike, Inc. + * Copyright 2012-2024 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0. @@ -33,7 +33,7 @@ public final class LatencyBuckets { * * @param latencyColumns number of latency buckets * @param latencyShift power of 2 multiple between each range bucket in latency histograms starting at bucket 3. - * The first 2 buckets are "<=1ms" and ">1ms". + * The first 2 buckets are "<=1ms" and ">1ms". */ public LatencyBuckets(int latencyColumns, int latencyShift) { this.latencyShift = latencyShift; diff --git a/client/src/com/aerospike/client/metrics/LatencyType.java b/client/src/com/aerospike/client/metrics/LatencyType.java index 01fda6aa2..625a9ef07 100644 --- a/client/src/com/aerospike/client/metrics/LatencyType.java +++ b/client/src/com/aerospike/client/metrics/LatencyType.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 Aerospike, Inc. + * Copyright 2012-2024 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0. @@ -16,6 +16,9 @@ */ package com.aerospike.client.metrics; +/** + * Latency group type. + */ public enum LatencyType { CONN, WRITE, diff --git a/client/src/com/aerospike/client/metrics/MetricsPolicy.java b/client/src/com/aerospike/client/metrics/MetricsPolicy.java index df6e285a3..b6119027e 100644 --- a/client/src/com/aerospike/client/metrics/MetricsPolicy.java +++ b/client/src/com/aerospike/client/metrics/MetricsPolicy.java @@ -69,7 +69,7 @@ public final class MetricsPolicy { /** * Power of 2 multiple between each range bucket in latency histograms starting at column 3. The bucket units - * are in milliseconds. The first 2 buckets are "<=1ms" and ">1ms". Examples: + * are in milliseconds. The first 2 buckets are "<=1ms" and ">1ms". Examples: *
{@code
 	 * // latencyColumns=7 latencyShift=1
 	 * <=1ms >1ms >2ms >4ms >8ms >16ms >32ms
diff --git a/client/src/com/aerospike/client/policy/ReadModeSC.java b/client/src/com/aerospike/client/policy/ReadModeSC.java
index ff2c6dbd3..eed429b13 100644
--- a/client/src/com/aerospike/client/policy/ReadModeSC.java
+++ b/client/src/com/aerospike/client/policy/ReadModeSC.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2021 Aerospike, Inc.
+ * Copyright 2012-2024 Aerospike, Inc.
  *
  * Portions may be licensed to Aerospike, Inc. under one or more contributor
  * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
@@ -24,25 +24,25 @@
 public enum ReadModeSC {
 	/**
 	 * Ensures this client will only see an increasing sequence of record versions.
-	 * Server only reads from master.  This is the default.
+	 * Client only reads from master. This is the default.
 	 */
 	SESSION,
 
 	/**
-	 * Ensures ALL clients will only see an increasing sequence of record versions.
-	 * Server only reads from master.
+	 * Ensures all clients will only see an increasing sequence of record versions.
+	 * Client only reads from master.
 	 */
 	LINEARIZE,
 
 	/**
-	 * Server may read from master or any full (non-migrating) replica.
+	 * Client may read from master or any full (non-migrating) replica.
 	 * Increasing sequence of record versions is not guaranteed.
 	 */
 	ALLOW_REPLICA,
 
 	/**
-	 * Server may read from master or any full (non-migrating) replica or from unavailable
-	 * partitions.  Increasing sequence of record versions is not guaranteed.
+	 * Client may read from master or any full (non-migrating) replica or from unavailable
+	 * partitions. Increasing sequence of record versions is not guaranteed.
 	 */
 	ALLOW_UNAVAILABLE
 }
diff --git a/client/src/com/aerospike/client/query/QueryAggregateExecutor.java b/client/src/com/aerospike/client/query/QueryAggregateExecutor.java
index 614d6aa26..b4860c401 100644
--- a/client/src/com/aerospike/client/query/QueryAggregateExecutor.java
+++ b/client/src/com/aerospike/client/query/QueryAggregateExecutor.java
@@ -18,8 +18,6 @@
 
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 
 import org.luaj.vm2.LuaInteger;
 import org.luaj.vm2.LuaValue;
diff --git a/client/src/com/aerospike/client/query/QueryExecutor.java b/client/src/com/aerospike/client/query/QueryExecutor.java
index fd2a21251..a50693429 100644
--- a/client/src/com/aerospike/client/query/QueryExecutor.java
+++ b/client/src/com/aerospike/client/query/QueryExecutor.java
@@ -16,9 +16,6 @@
  */
 package com.aerospike.client.query;
 
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
diff --git a/client/src/com/aerospike/client/task/IndexTask.java b/client/src/com/aerospike/client/task/IndexTask.java
index 98852e603..bdc469127 100644
--- a/client/src/com/aerospike/client/task/IndexTask.java
+++ b/client/src/com/aerospike/client/task/IndexTask.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2021 Aerospike, Inc.
+ * Copyright 2012-2024 Aerospike, Inc.
  *
  * Portions may be licensed to Aerospike, Inc. under one or more contributor
  * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
@@ -18,6 +18,7 @@
 
 import com.aerospike.client.AerospikeException;
 import com.aerospike.client.Info;
+import com.aerospike.client.ResultCode;
 import com.aerospike.client.cluster.Cluster;
 import com.aerospike.client.cluster.Node;
 import com.aerospike.client.policy.Policy;
@@ -92,13 +93,14 @@ public static int parseStatusResponse(String command, String response, boolean i
 			int index = response.indexOf(find);
 
 			if (index < 0) {
-				if (response.indexOf("FAIL:201") >= 0 || response.indexOf("FAIL:203") >= 0) {
-					// Index not found or not readable.
+				Info.Error error = new Info.Error(response);
+
+				if (error.code == ResultCode.INDEX_NOTFOUND || error.code == ResultCode.INDEX_NOTREADABLE) {
 					return Task.NOT_FOUND;
 				}
 				else {
 					// Throw exception immediately.
-					throw new AerospikeException(command + " failed: " + response);
+					throw new AerospikeException(error.code, command + " failed: " + error.message);
 				}
 			}
 
@@ -113,7 +115,9 @@ public static int parseStatusResponse(String command, String response, boolean i
 		}
 		else {
 			// Check if index has been dropped.
-			if (response.indexOf("FAIL:201") < 0) {
+			Info.Error error = new Info.Error(response);
+
+			if (error.code != ResultCode.INDEX_NOTFOUND) {
 				// Index still exists.
 				return Task.IN_PROGRESS;
 			}
diff --git a/examples/pom.xml b/examples/pom.xml
index 318c231be..c3f381888 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -6,7 +6,7 @@
   
     com.aerospike
     aerospike-parent
-    8.1.1
+    8.1.2
   
   aerospike-examples
   jar
diff --git a/pom.xml b/pom.xml
index f22dbf19c..3f9c5ddea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
   com.aerospike
   aerospike-parent
   aerospike-parent
-  8.1.1
+  8.1.2
   pom
   https://github.com/aerospike/aerospike-client-java
 
@@ -39,12 +39,12 @@
     2.18.1
     3.2.0
 
-    4.1.108.Final
+    4.1.110.Final
     2.0.62.Final
     1.59.0
     3.0.1
     0.4
-    1.7.0
+    1.8.0
     4.13.1
   
 
diff --git a/proxy/pom.xml b/proxy/pom.xml
index 0c269eb7f..b458324de 100644
--- a/proxy/pom.xml
+++ b/proxy/pom.xml
@@ -6,7 +6,7 @@
   
     com.aerospike
     aerospike-parent
-    8.1.1
+    8.1.2
   
   aerospike-proxy-client
   jar
diff --git a/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java b/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java
index 46a051d91..eca2fe93a 100644
--- a/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java
+++ b/proxy/src/com/aerospike/client/proxy/AerospikeClientProxy.java
@@ -1289,7 +1289,9 @@ public void get(EventLoop eventLoop, RecordArrayListener listener, BatchPolicy p
 			policy = batchPolicyDefault;
 		}
 
-		CommandProxy command = new BatchProxy.GetArrayCommand(executor, policy, listener, keys, binNames, null, Command.INFO1_READ, false);
+		int readAttr = (binNames == null || binNames.length == 0)? Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ;
+
+		CommandProxy command = new BatchProxy.GetArrayCommand(executor, policy, listener, keys, binNames, null, readAttr, false);
 		command.execute();
 	}
 
@@ -1317,7 +1319,9 @@ public void get(EventLoop eventLoop, RecordSequenceListener listener, BatchPolic
 			policy = batchPolicyDefault;
 		}
 
-		CommandProxy command = new BatchProxy.GetSequenceCommand(executor, policy, listener, keys, binNames, null, Command.INFO1_READ, false);
+		int readAttr = (binNames == null || binNames.length == 0)? Command.INFO1_READ | Command.INFO1_GET_ALL : Command.INFO1_READ;
+
+		CommandProxy command = new BatchProxy.GetSequenceCommand(executor, policy, listener, keys, binNames, null, readAttr, false);
 		command.execute();
 	}
 
diff --git a/test/pom.xml b/test/pom.xml
index 218b6c7ba..e7c55b8ee 100644
--- a/test/pom.xml
+++ b/test/pom.xml
@@ -6,7 +6,7 @@
   
     com.aerospike
     aerospike-parent
-    8.1.1
+    8.1.2
   
   aerospike-client-test
   jar
diff --git a/test/src/com/aerospike/test/async/TestAsyncQuery.java b/test/src/com/aerospike/test/async/TestAsyncQuery.java
index fe4a8199a..daa34e49d 100644
--- a/test/src/com/aerospike/test/async/TestAsyncQuery.java
+++ b/test/src/com/aerospike/test/async/TestAsyncQuery.java
@@ -29,7 +29,6 @@
 import com.aerospike.client.ResultCode;
 import com.aerospike.client.listener.RecordSequenceListener;
 import com.aerospike.client.listener.WriteListener;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.Statement;
diff --git a/test/src/com/aerospike/test/sync/basic/TestBatch.java b/test/src/com/aerospike/test/sync/basic/TestBatch.java
index 90afd5765..82b7083ed 100644
--- a/test/src/com/aerospike/test/sync/basic/TestBatch.java
+++ b/test/src/com/aerospike/test/sync/basic/TestBatch.java
@@ -144,6 +144,30 @@ public void batchReads () {
 		}
 	}
 
+	@Test
+	public void batchReadsEmptyBinNames() {
+		Key[] keys = new Key[Size];
+		for (int i = 0; i < Size; i++) {
+			keys[i] = new Key(args.namespace, args.set, KeyPrefix + (i + 1));
+		}
+
+		String[] binNames = new String[] {};
+		Record[] records = client.get(null, keys, binNames);
+		assertEquals(Size, records.length);
+
+		for (int i = 0; i < records.length; i++) {
+			Key key = keys[i];
+			Record record = records[i];
+
+			if (i != 5) {
+				assertBinEqual(key, record, BinName, ValuePrefix + (i + 1));
+			}
+			else {
+				assertBinEqual(key, record, BinName, i + 1);
+			}
+		}
+	}
+
 	@Test
 	public void batchReadHeaders () {
 		Key[] keys = new Key[Size];
@@ -168,7 +192,7 @@ public void batchReadHeaders () {
 	}
 
 	@Test
-	public void batchReadComplex () {
+	public void batchReadComplex() {
 		// Batch allows multiple namespaces in one call, but example test environment may only have one namespace.
 
 		// bin * 8
@@ -179,7 +203,7 @@ public void batchReadComplex () {
 		List records = new ArrayList();
 		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 1), bins));
 		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 2), true));
-		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 3), true));
+		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 3), new String[] {}));
 		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 4), false));
 		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 5), true));
 		records.add(new BatchRead(new Key(args.namespace, args.set, KeyPrefix + 6), ops));
diff --git a/test/src/com/aerospike/test/sync/basic/TestPutGet.java b/test/src/com/aerospike/test/sync/basic/TestPutGet.java
index e2f99cd42..58830abee 100644
--- a/test/src/com/aerospike/test/sync/basic/TestPutGet.java
+++ b/test/src/com/aerospike/test/sync/basic/TestPutGet.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2023 Aerospike, Inc.
+ * Copyright 2012-2024 Aerospike, Inc.
  *
  * Portions may be licensed to Aerospike, Inc. under one or more contributor
  * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
@@ -41,6 +41,11 @@ public void putGet() {
 		Record record = client.get(null, key);
 		assertBinEqual(key, record, bin1);
 		assertBinEqual(key, record, bin2);
+
+		// Test empty binNames array.
+		record = client.get(null, key, new String[] {});
+		assertBinEqual(key, record, bin1);
+		assertBinEqual(key, record, bin2);
 	}
 
 	@Test
diff --git a/test/src/com/aerospike/test/sync/basic/TestScan.java b/test/src/com/aerospike/test/sync/basic/TestScan.java
index d0b3e1762..c6a29289f 100644
--- a/test/src/com/aerospike/test/sync/basic/TestScan.java
+++ b/test/src/com/aerospike/test/sync/basic/TestScan.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2023 Aerospike, Inc.
+ * Copyright 2012-2024 Aerospike, Inc.
  *
  * Portions may be licensed to Aerospike, Inc. under one or more contributor
  * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
@@ -35,6 +35,10 @@ public class TestScan extends TestSync implements ScanCallback {
 	public void scanParallel() {
 		ScanPolicy policy = new ScanPolicy();
 		client.scanAll(policy, args.namespace, args.set, this);
+
+		// Test empty binNames.
+		String[] binNames = new String[] {};
+		client.scanAll(policy, args.namespace, args.set, this, binNames);
 	}
 
 	@Test
diff --git a/test/src/com/aerospike/test/sync/basic/TestServerInfo.java b/test/src/com/aerospike/test/sync/basic/TestServerInfo.java
index f3f52424a..2d39bf2bf 100644
--- a/test/src/com/aerospike/test/sync/basic/TestServerInfo.java
+++ b/test/src/com/aerospike/test/sync/basic/TestServerInfo.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2012-2023 Aerospike, Inc.
+ * Copyright 2012-2024 Aerospike, Inc.
  *
  * Portions may be licensed to Aerospike, Inc. under one or more contributor
  * license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
@@ -17,9 +17,11 @@
 package com.aerospike.test.sync.basic;
 
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertEquals;
 
 import java.util.Map;
 
+import com.aerospike.client.ResultCode;
 import org.junit.Test;
 
 import com.aerospike.client.Info;
@@ -76,4 +78,33 @@ private void LogNameValueTokens(String tokens) {
 			assertNotNull(value);
 		}
 	}
+
+	@Test
+	public void errorResponse() {
+		Info.Error error;
+
+		error = new Info.Error("FaIL:201:index not found");
+		assertEquals(error.code, 201);
+		assertEquals(error.message, "index not found");
+
+		error = new Info.Error("ERRor:201:index not found");
+		assertEquals(error.code, 201);
+		assertEquals(error.message, "index not found");
+
+		error = new Info.Error("error::index not found ");
+		assertEquals(error.code, ResultCode.CLIENT_ERROR);
+		assertEquals(error.message, "index not found");
+
+		error = new Info.Error("error: index not found ");
+		assertEquals(error.code, ResultCode.CLIENT_ERROR);
+		assertEquals(error.message, "index not found");
+
+		error = new Info.Error("error:99");
+		assertEquals(error.code, 99);
+		assertEquals(error.message, "error:99");
+
+		error = new Info.Error("generic message");
+		assertEquals(error.code, ResultCode.CLIENT_ERROR);
+		assertEquals(error.message, "generic message");
+	}
 }
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryAverage.java b/test/src/com/aerospike/test/sync/query/TestQueryAverage.java
index 02c47ab89..98060d825 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryAverage.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryAverage.java
@@ -30,7 +30,6 @@
 import com.aerospike.client.Key;
 import com.aerospike.client.Language;
 import com.aerospike.client.ResultCode;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.ResultSet;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryBlob.java b/test/src/com/aerospike/test/sync/query/TestQueryBlob.java
index d7f1587bb..5362799b4 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryBlob.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryBlob.java
@@ -32,7 +32,6 @@
 import com.aerospike.client.Key;
 import com.aerospike.client.Record;
 import com.aerospike.client.command.Buffer;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexCollectionType;
 import com.aerospike.client.query.IndexType;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryCollection.java b/test/src/com/aerospike/test/sync/query/TestQueryCollection.java
index 5736a8391..78bc92a8e 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryCollection.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryCollection.java
@@ -32,7 +32,6 @@
 import com.aerospike.client.Language;
 import com.aerospike.client.Record;
 import com.aerospike.client.ResultCode;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexCollectionType;
 import com.aerospike.client.query.IndexType;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryContext.java b/test/src/com/aerospike/test/sync/query/TestQueryContext.java
index cbc1e448c..b921c5439 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryContext.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryContext.java
@@ -32,7 +32,6 @@
 import com.aerospike.client.Record;
 import com.aerospike.client.ResultCode;
 import com.aerospike.client.cdt.CTX;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexCollectionType;
 import com.aerospike.client.query.IndexType;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryExecute.java b/test/src/com/aerospike/test/sync/query/TestQueryExecute.java
index 470af26a7..84b2d35e1 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryExecute.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryExecute.java
@@ -35,7 +35,6 @@
 import com.aerospike.client.exp.ExpOperation;
 import com.aerospike.client.exp.ExpWriteFlags;
 import com.aerospike.client.exp.Expression;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.RecordSet;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryFilter.java b/test/src/com/aerospike/test/sync/query/TestQueryFilter.java
index f49e9cf94..198e0877b 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryFilter.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryFilter.java
@@ -31,7 +31,6 @@
 import com.aerospike.client.Language;
 import com.aerospike.client.ResultCode;
 import com.aerospike.client.Value;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.ResultSet;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryFilterExp.java b/test/src/com/aerospike/test/sync/query/TestQueryFilterExp.java
index 94d1653b7..b3f6ff862 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryFilterExp.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryFilterExp.java
@@ -37,7 +37,6 @@
 import com.aerospike.client.exp.Exp;
 import com.aerospike.client.exp.ListExp;
 import com.aerospike.client.exp.MapExp;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.policy.QueryPolicy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryGeo.java b/test/src/com/aerospike/test/sync/query/TestQueryGeo.java
index 692941066..4bf7f5c0f 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryGeo.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryGeo.java
@@ -27,7 +27,6 @@
 import com.aerospike.client.Key;
 import com.aerospike.client.ResultCode;
 import com.aerospike.client.exp.Exp;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.policy.QueryPolicy;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.RecordSet;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryInteger.java b/test/src/com/aerospike/test/sync/query/TestQueryInteger.java
index 186ef6f42..57c467b83 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryInteger.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryInteger.java
@@ -26,7 +26,6 @@
 import com.aerospike.client.Bin;
 import com.aerospike.client.Key;
 import com.aerospike.client.ResultCode;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.RecordSet;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryKey.java b/test/src/com/aerospike/test/sync/query/TestQueryKey.java
index c986c70ac..d06dc5f72 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryKey.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryKey.java
@@ -27,7 +27,6 @@
 import com.aerospike.client.Bin;
 import com.aerospike.client.Key;
 import com.aerospike.client.ResultCode;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.policy.WritePolicy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryRPS.java b/test/src/com/aerospike/test/sync/query/TestQueryRPS.java
index 59bca48fe..d2cac77b1 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryRPS.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryRPS.java
@@ -30,7 +30,6 @@
 import com.aerospike.client.ResultCode;
 import com.aerospike.client.Value;
 import com.aerospike.client.cluster.Node;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.RecordSet;
diff --git a/test/src/com/aerospike/test/sync/query/TestQueryString.java b/test/src/com/aerospike/test/sync/query/TestQueryString.java
index 92a2ea96a..4803a5a8c 100644
--- a/test/src/com/aerospike/test/sync/query/TestQueryString.java
+++ b/test/src/com/aerospike/test/sync/query/TestQueryString.java
@@ -28,7 +28,6 @@
 import com.aerospike.client.Key;
 import com.aerospike.client.Record;
 import com.aerospike.client.ResultCode;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;
 import com.aerospike.client.query.RecordSet;
@@ -95,4 +94,33 @@ public void queryString() {
 			rs.close();
 		}
 	}
+
+	@Test
+	public void queryStringEmptyBinName() {
+		String filter = valuePrefix + 3;
+
+		Statement stmt = new Statement();
+		stmt.setNamespace(args.namespace);
+		stmt.setSetName(args.set);
+		stmt.setBinNames(new String[] {});
+		stmt.setFilter(Filter.equal(binName, filter));
+
+		RecordSet rs = client.query(null, stmt);
+
+		try {
+			int count = 0;
+
+			while (rs.next()) {
+				Record record = rs.getRecord();
+				String result = record.getString(binName);
+				assertEquals(filter, result);
+				count++;
+			}
+
+			assertNotEquals(0, count);
+		}
+		finally {
+			rs.close();
+		}
+	}
 }
diff --git a/test/src/com/aerospike/test/sync/query/TestQuerySum.java b/test/src/com/aerospike/test/sync/query/TestQuerySum.java
index ce7042095..0ba4247d4 100644
--- a/test/src/com/aerospike/test/sync/query/TestQuerySum.java
+++ b/test/src/com/aerospike/test/sync/query/TestQuerySum.java
@@ -30,7 +30,6 @@
 import com.aerospike.client.Language;
 import com.aerospike.client.ResultCode;
 import com.aerospike.client.Value;
-import com.aerospike.client.policy.Policy;
 import com.aerospike.client.policy.QueryPolicy;
 import com.aerospike.client.query.Filter;
 import com.aerospike.client.query.IndexType;