aerospike / aerospike-client-java Goto Github PK
View Code? Open in Web Editor NEWAerospike Java Client Library
License: Other
Aerospike Java Client Library
License: Other
I want to avoid data convertions that happen when client converts policy, namespaces, set names, keys to byte array. I.e. in Command
and in Key
Instead I want to see something like
public byte[] get(byte[] policy, byte[] key) throws AerospikeException;
// or
public byte[] get(byte[] policy, byte[] namespace, byte[] set, byte[] keyHash) throws AerospikeException;
Whant do you think?
I made some tests with the AsyncClient. Unfortunately there are several problems. I don't have the feeling that this is really ready for production :(
So far I only tested a client.get with a RecordListener.
At first I figured out that all the exceptions in the methods onSuccess and onFailure of a RecordListener will we swallowed. When you want to change it, you should print the exception in
com.aerospike.client.async.SelectorManager line 100.
I set an expiration of -1 but the record shows me an expiration of 0 for the same value. This is a bit inconsistent.
In my tests I closed the client before the RecordListener could return any results of a client.get() call. With aerospike-client-3.0.35.jar this will lead to a deadlock in 100 % of all cases. The java program won't terminate.
With the latest source code a deadlock only occurs in some cases. But this must be fixed. Your client must always shut down gracefully! In my test cases I never used a local Aerospike server. This means there was always a high network latency.
Hopefully this stack will help you:
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.75-b04 mixed mode):
"RMI TCP Connection(2)-" daemon prio=6 tid=0x000000000a70f000 nid=0x1770 runnable [0x000000000ba7e000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
- locked <0x00000000eb333e68> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- <0x00000000eb042fe8> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"JMX server connection timeout 15" daemon prio=6 tid=0x000000000a5c0800 nid=0x16c8 in Object.wait() [0x000000000b96f000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eb18d518> (a [I)
at com.sun.jmx.remote.internal.ServerCommunicatorAdmin$Timeout.run(Unknown Source)
- locked <0x00000000eb18d518> (a [I)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- None
"RMI Scheduler(0)" daemon prio=6 tid=0x00000000095d0000 nid=0x7f4 waiting on condition [0x000000000b73e000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000eaf9a980> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- None
"RMI TCP Connection(1)-" daemon prio=6 tid=0x00000000095cf800 nid=0x1648 runnable [0x000000000b54e000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.io.BufferedInputStream.fill(Unknown Source)
at java.io.BufferedInputStream.read(Unknown Source)
- locked <0x00000000eb0e47b0> (a java.io.BufferedInputStream)
at java.io.FilterInputStream.read(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.access$400(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- <0x00000000eb03fb00> (a java.util.concurrent.ThreadPoolExecutor$Worker)
"RMI TCP Accept-0" daemon prio=6 tid=0x00000000098c8000 nid=0x1618 runnable [0x000000000b2ce000]
java.lang.Thread.State: RUNNABLE
at java.net.DualStackPlainSocketImpl.accept0(Native Method)
at java.net.DualStackPlainSocketImpl.socketAccept(Unknown Source)
at java.net.AbstractPlainSocketImpl.accept(Unknown Source)
at java.net.PlainSocketImpl.accept(Unknown Source)
- locked <0x00000000eaf9e748> (a java.net.SocksSocketImpl)
at java.net.ServerSocket.implAccept(Unknown Source)
at java.net.ServerSocket.accept(Unknown Source)
at sun.management.jmxremote.LocalRMIServerSocketFactory$1.accept(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.executeAcceptLoop(Unknown Source)
at sun.rmi.transport.tcp.TCPTransport$AcceptLoop.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Locked ownable synchronizers:
- None
"selector0" daemon prio=6 tid=0x000000000989d800 nid=0xc10 waiting for monitor entry [0x000000000a0af000]
java.lang.Thread.State: BLOCKED (on object monitor)
at sun.nio.ch.WindowsSelectorImpl.putEventOps(Unknown Source)
- waiting to lock <0x00000000eab790d8> (a java.lang.Object)
at sun.nio.ch.SocketChannelImpl.translateAndSetInterestOps(Unknown Source)
at sun.nio.ch.SelectionKeyImpl.nioInterestOps(Unknown Source)
at sun.nio.ch.SelectionKeyImpl.interestOps(Unknown Source)
at sun.nio.ch.SelectorImpl.register(Unknown Source)
at java.nio.channels.spi.AbstractSelectableChannel.register(Unknown Source)
- locked <0x00000000eacf6c00> (a java.lang.Object)
- locked <0x00000000eacf6c10> (a java.lang.Object)
at com.aerospike.client.async.AsyncConnection.register(AsyncConnection.java:86)
at com.aerospike.client.async.SelectorManager.registerCommands(SelectorManager.java:129)
at com.aerospike.client.async.SelectorManager.runCommands(SelectorManager.java:85)
at com.aerospike.client.async.SelectorManager.run(SelectorManager.java:69)
Locked ownable synchronizers:
- None
"Service Thread" daemon prio=6 tid=0x0000000007df0000 nid=0x106c runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread1" daemon prio=10 tid=0x0000000007ded000 nid=0xa04 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"C2 CompilerThread0" daemon prio=10 tid=0x0000000007dde800 nid=0x1488 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Attach Listener" daemon prio=10 tid=0x0000000007ddd000 nid=0x1624 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Signal Dispatcher" daemon prio=10 tid=0x0000000007ddb800 nid=0x10e8 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Finalizer" daemon prio=8 tid=0x0000000007d89800 nid=0x7d8 in Object.wait() [0x0000000008c3f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eaa84858> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
- locked <0x00000000eaa84858> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
Locked ownable synchronizers:
- None
"Reference Handler" daemon prio=10 tid=0x0000000001d2c000 nid=0x1540 in Object.wait() [0x000000000890f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000eaa84470> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:503)
at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
- locked <0x00000000eaa84470> (a java.lang.ref.Reference$Lock)
Locked ownable synchronizers:
- None
"main" prio=6 tid=0x0000000001d5d800 nid=0x1420 waiting for monitor entry [0x000000000208f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at java.nio.channels.spi.AbstractSelectableChannel.removeKey(Unknown Source)
- waiting to lock <0x00000000eacf6c00> (a java.lang.Object)
at java.nio.channels.spi.AbstractSelector.deregister(Unknown Source)
at sun.nio.ch.WindowsSelectorImpl.implClose(Unknown Source)
- locked <0x00000000eab790d8> (a java.lang.Object)
at sun.nio.ch.SelectorImpl.implCloseSelector(Unknown Source)
- locked <0x00000000eab78e58> (a sun.nio.ch.Util$2)
- locked <0x00000000eab78df0> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000eab78bd8> (a sun.nio.ch.WindowsSelectorImpl)
at java.nio.channels.spi.AbstractSelector.close(Unknown Source)
at com.aerospike.client.async.SelectorManager.close(SelectorManager.java:201)
at com.aerospike.client.async.SelectorManagers.close(SelectorManagers.java:65)
at com.aerospike.client.async.AsyncCluster.close(AsyncCluster.java:86)
at com.aerospike.client.AerospikeClient.close(AerospikeClient.java:233)
at Test.main(Test.java:130)
Locked ownable synchronizers:
- None
"VM Thread" prio=10 tid=0x0000000007d82000 nid=0x1734 runnable
"GC task thread#0 (ParallelGC)" prio=6 tid=0x0000000001c64000 nid=0x1144 runnable
"GC task thread#1 (ParallelGC)" prio=6 tid=0x0000000001c66000 nid=0x15d0 runnable
"VM Periodic Task Thread" prio=10 tid=0x0000000007df9800 nid=0x15d8 waiting on condition
JNI global references: 167
"selector0":
waiting to lock monitor 0x0000000007d896d8 (object 0x00000000eab790d8, a java.lang.Object),
which is held by "main"
"main":
waiting to lock monitor 0x0000000007d88028 (object 0x00000000eacf6c00, a java.lang.Object),
which is held by "selector0"
"selector0":
at sun.nio.ch.WindowsSelectorImpl.putEventOps(Unknown Source)
- waiting to lock <0x00000000eab790d8> (a java.lang.Object)
at sun.nio.ch.SocketChannelImpl.translateAndSetInterestOps(Unknown Source)
at sun.nio.ch.SelectionKeyImpl.nioInterestOps(Unknown Source)
at sun.nio.ch.SelectionKeyImpl.interestOps(Unknown Source)
at sun.nio.ch.SelectorImpl.register(Unknown Source)
at java.nio.channels.spi.AbstractSelectableChannel.register(Unknown Source)
- locked <0x00000000eacf6c00> (a java.lang.Object)
- locked <0x00000000eacf6c10> (a java.lang.Object)
at com.aerospike.client.async.AsyncConnection.register(AsyncConnection.java:86)
at com.aerospike.client.async.SelectorManager.registerCommands(SelectorManager.java:129)
at com.aerospike.client.async.SelectorManager.runCommands(SelectorManager.java:85)
at com.aerospike.client.async.SelectorManager.run(SelectorManager.java:69)
"main":
at java.nio.channels.spi.AbstractSelectableChannel.removeKey(Unknown Source)
- waiting to lock <0x00000000eacf6c00> (a java.lang.Object)
at java.nio.channels.spi.AbstractSelector.deregister(Unknown Source)
at sun.nio.ch.WindowsSelectorImpl.implClose(Unknown Source)
- locked <0x00000000eab790d8> (a java.lang.Object)
at sun.nio.ch.SelectorImpl.implCloseSelector(Unknown Source)
- locked <0x00000000eab78e58> (a sun.nio.ch.Util$2)
- locked <0x00000000eab78df0> (a java.util.Collections$UnmodifiableSet)
- locked <0x00000000eab78bd8> (a sun.nio.ch.WindowsSelectorImpl)
at java.nio.channels.spi.AbstractSelector.close(Unknown Source)
at com.aerospike.client.async.SelectorManager.close(SelectorManager.java:201)
at com.aerospike.client.async.SelectorManagers.close(SelectorManagers.java:65)
at com.aerospike.client.async.AsyncCluster.close(AsyncCluster.java:86)
at com.aerospike.client.AerospikeClient.close(AerospikeClient.java:233)
at Test.main(Test.java:130)
Found 1 deadlock.
The class com.aerospike.client.Bin
overrides equals, but not hashcode. This leads to incorrect behavior when instances are used in hash-based structures (such as HashMap
).
It would save me a whole bunch of lines of code in my unit tests if com.aerospike.client.query.Filter
overrode equals
and hashcode
.
Client cannot execute "scan", "config" and the exception com.aerospike.client.AerospikeException: Error Code 1417: /opt/aerospike/sys/udf/lua/ldt/lib_lmap.lua:868 LDT-Bin Does Not Exist is flow
WritePolicy policy = new WritePolicy();
policy.sendKey= true;
Key key = new Key(SystemVariable.DEFAULT_NAME_SPACE, Account.class, uuid);
LargeMap lg= ((LargeMap)aerospikeClient.getLargeMap(policy, key, "userGroupMap", null));
Map map = lg.getConfig(); //ERROR Map<String,String>
if (lg.size()>0){ //ERROR
}
com.aerospike.client.AerospikeException: Error Code 1417: /opt/aerospike/sys/udf/lua/ldt/lib_lmap.lua:868 LDT-Bin Does Not Exist
at com.aerospike.client.command.ReadCommand.handleUdfError(ReadCommand.java:157)
at com.aerospike.client.command.ReadCommand.parseResult(ReadCommand.java:118)
at com.aerospike.client.command.SyncCommand.execute(SyncCommand.java:56)
at com.aerospike.client.AerospikeClient.execute(AerospikeClient.java:1145)
at com.aerospike.client.large.LargeMap.getConfig(LargeMap.java:145)
Calling AerospikeClient.get(Policy policy, Key[] keys) never returns WHEN an EMPTY ARRAY of keys is specified. It blocks forever and never comes back.
This should either throw an exception or return instantly with an empty Array or Records.
Scenario: I want to put a value using client's default write policy, but I want to set expiration time for the record. If I use the AerospikeClient
class I can do that like this:
AerospikeClient client = getClient();
WritePolicy policy = new WritePolicy(client.writePolicyDefault);
policy.expiration = 10;
client.put(policy, key, bin);
But I cannot access writePolicyDefault
if I use the IAerospikeClient
interface.
Please either create getters for default policies in the interfaces or provide another way to apply a modified default policy for an operation.
When i do some benchmarks, inserting a lot of records (a key and a bin of 1 kbytes), i see all my indicators (CPU, IO network and disk) at a very low level. But the result is not so good (20000 records/sec ==> 25 Mbytes/sec). I think it's due to network and client/server latency. So with methods for a batch write (and batch delete) , i'm sure i could go more faster!
The LargeMap.get function should return an empty Map.
It would also be nice if an "exists(key)" function was created otherwise there should be a function that can be used to determine if a key exists in the LargeMap without throwing an exception.
The following is the exception:
[error] AerospikeException: Error Code 1401: /opt/aerospike/sys/udf/lua/ldt/lib_lmap.lua:2976 LDT-Item Not Found (ReadCommand.java:137)
[error] com.aerospike.client.command.ReadCommand.handleUdfError(ReadCommand.java:137)
[error] com.aerospike.client.command.ReadCommand.parseResult(ReadCommand.java:106)
[error] com.aerospike.client.command.SyncCommand.execute(SyncCommand.java:56)
[error] com.aerospike.client.AerospikeClient.execute(AerospikeClient.java:848)
[error] com.aerospike.client.large.LargeMap.get(LargeMap.java:82)
I am performing this for a record which has binvalues of types double and list.
Key key = new Key(namespace,set,recordKey);
Record record = aerospikeClient.get(null, key);
The value for record.bins.get("binName").getClass()
is always class java.lang.String
irrespective of the bin value. Is this the expected behavior?
I cannot open most pages of java client documentation. I.e.
http://www.aerospike.com/docs/client/java/usage/scan/scan.html
http://www.aerospike.com/docs/client/java/usage/kvs
http://www.aerospike.com/docs/client/java/usage/udf
etc
It would be very helpful to have an asynchronous equivalent to AerospikeClient.queryAggregate()
. This feature gap prevents the use of AsyncClient
in applications which require aggregation.
Sometimes there is a need to have Double values mixed with Integer values in Aerospike. E.g. some job inserts double values, but when it comes to 0 or other integer it simply inserts 0 instead of 0.0 or 5 instead of 5.0. But in Aerospike client it's not convenient to try-cast value to any type. Java is OK to convert int to double, so there should be no problem to do that in Aerospike driver.
Steps to reproduce:
Expected:
3. There's a value converted to double, e.g. 0.0 or 5.0
Actual:
3.
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
at com.aerospike.client.Record.getDouble(Record.java:77)
....
Short test to reproduce:
@Test
public void testGetDoubleWhenIntInserted() {
Map<String, Object> vals = new HashMap<>();
vals.put("value", 5);
Record record = new Record(vals, 1, 1);
record.getDouble("value");
}
Aerospike client version:
3.3.0
AerospikeClient#get(Policy policy, Key[] keys, String... binNames) operation throws a null pointer exception when I pass in a null policy. This behaviour seems to conflict with its documentation:
@param policy generic configuration parameters, pass in null for defaults
This behaviour may be present in other batch operations using the BatchExecutor:
The Exception:
com.aerospike.client.AerospikeException: java.lang.NullPointerException at com.aerospike.client.command.BatchExecutor.<init>(BatchExecutor.java:86)
I am using version 3.1.2 of the client and am trying to make a query which contains the following code
Statement stmt = new Statement();
stmt.setNamespace("ns");
stmt.setSetName("set");
stmt.setFilters( Filter.equal("foo", "someFoo"), Filter.equal("bar", "someBar") );
RecordSet rs = asClient.query(null, stmt);
while (rs.next()) {
// etc..
}
So the corresponding aql would be something like
SELECT * FROM ns.set WHERE foo = 'someFoo' AND bar = 'someBar'
Both foo
and bar
have a secondary index and the corresponding aql statement works as expected. There's also nothing in the logs regarding any indication of any error. When I only use one filter, the query works fine.
However, when I execute that statement and try and retrieve the records I get an AerospikeException
saying Error Code 4: Parameter Error
.
I could not find anything in the Java Client Documentation or in the JavaDocs about this issue. The only thing I could find was a response to a question from almost a year ago saying that multiple equal filters were not supported. I also couldn't find a changelog between clients so I'm not sure if this is still the case. If it's not the case, is there any way I can get more visibility into what it is I'm doing wrong? If it is still the case, could you maybe please make that fact more apparent in the documentation?
The javadoc comments on com.aerospike.client.query.Filter.range
(two methods) don't specify whether the begin
and end
parameters are inclusive or exclusive. Assuming the wrong meaning is an easy way to introduce subtle bugs into an application.
see here: https://discuss.aerospike.com/t/error-code-204-index-error-in-small-geo-test-program/2484/5
under german locale settings this new GeoJSONValue("{ \"type\": \"Point\", \"coordinates\": [50, 50] }"));
is parsed like ...[50.50]... which is not a valid point coordinate. The meaning "," and "." in numeric locale is swapped between LANG=de_DE.UTF-8 and LANG=C.
Andreas
I simply want to add a value onto the end of a list. It does not appear that I can do this via the regular api so I am trying to write a lua function that will do it for me.
Every time I try to register my lua file I get this error --
Exception in thread "main" com.aerospike.client.AerospikeException: Registration failed: invalid_content_len
File: null
Line: null
Message: null
at com.aerospike.client.AerospikeClient.registerContent(AerospikeClient.java:1014)
at com.aerospike.client.AerospikeClient.register(AerospikeClient.java:951)
at com.alianza.aerospiketest.Main.main(Main.java:36)
Here is my example code
import com.aerospike.client.AerospikeClient;
import com.aerospike.client.policy.ClientPolicy;
public class Main {
private static final String HOST = "host";
private static final String NAMESPACE = "namespace";
private static AerospikeClient client;
private static ClientPolicy policy;
public static void main(String[] args) {
client = new AerospikeClient(HOST, 3000);
policy = new ClientPolicy();
client.register(policy.readPolicyDefault, "/tmp/list_functions.lua", "list_functions.lua", com.aerospike.client.Language.LUA);
}
}
lua file -- list_functions.lua
function add_to_list(record, binname, value)
if record.MAIN == null then
record.MAIN = list()
end
list.append(record.MAIN, value)
aerospike:update(record)
end
Trying to create aerospike records, using the client e.g. version [com.aerospike/aerospike-client "3.0.34"]
or [com.aerospike/aerospike-client "3.0.20"]
results in the following error:
ClassCastException Cannot cast com.aerospike.client.Bin to [Lcom.aerospike.client.Bin; java.lang.Class.cast (Class.java:3133)
(ns todo-aerospike.domain.utils.db
(:import [com.aerospike.client Bin AerospikeClient Key Record Info]
[com.aerospike.client.cluster Node]
[com.aerospike.client.policy WritePolicy]))
(def key-namespace "todo-aerospike")
(def write-policy (new WritePolicy))
(defn uuid []
(str (java.util.UUID/randomUUID)))
(defn create [conn data]
"[C]RUD creates a record "
(let [bin (new Bin (:column-name data) (:value data))
key (new Key key-namespace (:set-name data) (uuid))]
(println (.getClass bin)) ; for Debug
(. conn put write-policy key bin)))
trying to create a record from the repl, results in the mentioned error
➜ todo-aerospike git:(master) ✗ lein repl
nREPL server started on port 53426 on host 127.0.0.1 - nrepl://127.0.0.1:53426
REPL-y 0.3.5, nREPL 0.2.6
Clojure 1.6.0
Java HotSpot(TM) 64-Bit Server VM 1.7.0_67-b01
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
=> (in-ns 'todo-aerospike.domain.utils.db)
=> (def conn (new AerospikeClient "localhost" 3000))
=> (first (.getNodes conn))
#<Node BB976C89B270008 127.0.0.1:3000>
=> (create conn { :column-name "test" :value "work you client" :set-name "test" })
com.aerospike.client.Bin
ClassCastException Cannot cast com.aerospike.client.Bin to [Lcom.aerospike.client.Bin; java.lang.Class.cast (Class.java:3133)
and this is the stacktrace
java.lang.ClassCastException: Cannot cast com.aerospike.client.Bin to [Lcom.aerospike.client.Bin;
at java.lang.Class.cast(Class.java:3133)
at clojure.lang.Reflector.boxArg(Reflector.java:427)
at clojure.lang.Reflector.boxArgs(Reflector.java:460)
at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:58)
at clojure.lang.Reflector.invokeInstanceMethod(Reflector.java:28)
at todo_aerospike.domain.utils.db$eval6145.invoke(form-init4786145880839548089.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6703)
at clojure.lang.Compiler.eval(Compiler.java:6666)
at clojure.core$eval.invoke(core.clj:2927)
at clojure.main$repl$read_eval_print__6625$fn__6628.invoke(main.clj:239)
at clojure.main$repl$read_eval_print__6625.invoke(main.clj:239)
at clojure.main$repl$fn__6634.invoke(main.clj:257)
at clojure.main$repl.doInvoke(main.clj:257)
at clojure.lang.RestFn.invoke(RestFn.java:1523)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__5548.invoke(interruptible_eval.clj:67)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.core$apply.invoke(core.clj:624)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1862)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:51)
at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__5590$fn__5593.invoke(interruptible_eval.clj:183)
at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__5583.invoke(interruptible_eval.clj:152)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
I want to creat an aerospike todo app to showcase the client API.
here is the github repo https://github.com/andreiursan/todo-aerospike
package com.aerospike.examples;
import com.aerospike.client.*;
public class DoubleBinTest {
public static void main(String[] args) throws Exception {
String host = "localhost";
int port = 3000;
AerospikeClient client = new AerospikeClient(null, host, port);
String namespace = "test";
String set = "putget";
Key key = new Key(namespace, set, "foo");
Bin testBin1 = new Bin("Double", new Double(0.5)); // works
Bin testBin2 = new Bin("double", 0.5); // fails
client.put(null, key, testBin1, testBin2);
Record record1 = client.get(null, key);
Object result1 = record1.getValue("Double");
System.out.println("Result Double bin value is " + result1);
Object result2 = record1.getValue("double");
if (result2 != null) {
System.out.println("Result double bin type should be java.lang.Double");
System.out.println("Result double bin type is " + result2.getClass()); // class java.lang.Long
System.out.println("Result double bin value is " + result2); // 4602678819172646912
}
client.delete(null, key);
}
}
gives this result:
Result double bin value is 0.5
Result Double bin type should be java.lang.Double
Result Double bin type is class java.lang.Long
Result Double bin value is 4602678819172646912
Hi,
During my local investigation I found that isConnected() always return true, if there is no nodes available.
My setup is done in a way that I have just one Aerospike instance.
After startup of my application I manually shutdown Aerospike instance and I expect that this method will return false (since there is no instance to connect to).
Instead it always returns true.
As I can see from sources this method could return false only in two cases:
Problem is that Tend thread never deletes last node even if it is unavailable.
from com.aerospike.client.cluster.Cluster:
switch (nodes.length) {
case 1:
// Single node clusters rely on whether it responded to info requests.
if (node.failures >= 5) {
// 5 consecutive info requests failed. Try seeds.
if (seedNodes(false)) { // <--- Is negation missed here ? it always return false in my case
removeList.add(node);
}
}
break;
seedNodes(false) return false in my case and It prevents thread from removing this last node.
And this is the root of this problem.
Is it correct behavior or I understood semantics of this method incorrectly ?
What is the most efficient way to do upserts in aerospike.
thanks in advance.
Make IAerospikeClient interface extend Closeable so it can be used in try-with-resources block.
try (IAerospikeClient client = new AerospikeClient(host, port)) {
...
}
We have an Aerospike installation with a round-robin reverse-proxy in front of the nodes (this is in practice a Kubernetes service).
This sometimes works, but for the same request often returns:
com.aerospike.client.AerospikeException: Error Code 4: Parameter error
at com.aerospike.client.command.MultiCommand.parseGroup(MultiCommand.java:96)
at com.aerospike.client.command.MultiCommand.parseResult(MultiCommand.java:71)
at com.aerospike.client.command.SyncCommand.execute(SyncCommand.java:57)
at com.aerospike.client.query.QueryExecutor$QueryThread.run(QueryExecutor.java:137)
If I reconfigure it so that the Kubernetes service only points to a single node then it works fine.
I am using version 3.2.4 of the Java client and 3.9.1 of the server. This is very similar to this issue:
aerospike/aerospike-client-go#97
Is a feature to Increment value of a particular bin by certain amount?
Hi!
How i can set priority for new background scan job? There is for C client for example: http://www.aerospike.com/apidocs/c/d1/dc3/structas__scan.html#ab6b0b8a77c04f8eeb67771589338fae7
When creating an async aerospike client and explicitly creating an asyncTaskThreadPool (i.e. not running on the same thread as the selector) and the client policy asyncSelectorTimeout is not explicitly set, the aerospike client may occasionally not issue a callback when executing nested reads (seems to be a race condition)
The code below illustrates an example of when the nested bulk call may sometimes hang:
public static void main(String[] args) throws Exception {
AsyncClientPolicy asyncClientPolicy = new AsyncClientPolicy();
asyncClientPolicy.asyncMaxCommands = 200;
asyncClientPolicy.asyncSelectorThreads = 1;
asyncClientPolicy.asyncTaskThreadPool = Executors.newFixedThreadPool(10);
// NOTE: Adding selector timeout seems to prevent the nested bulk call from hanging
//asyncClientPolicy.asyncSelectorTimeout = 1;
AsyncClient client = new AsyncClient(asyncClientPolicy, AEROSPIKE_HOST, AEROSPIKE_PORT);
client.get(new ReadPolicy(), new RecordListener() {
public void onSuccess(Key key, final Record record) {
// Bulk call below may never notify listener of success or error
client.get(new ReadPolicy(), new RecordArrayListener() {
...
keys);
}
public void onFailure(AerospikeException e) {
...
}
}, key);
}
}
The aerospike client selector seems to block when no timeout is specified and async tasks may not notify listeners of completion events.
Question is, is this expected behaviour and what is the recommended setting for the asyncSelectorTimeout variable (low or high value)?
Full code example:
import java.util.concurrent.Executors;
import com.aerospike.client.AerospikeException;
import com.aerospike.client.Key;
import com.aerospike.client.Record;
import com.aerospike.client.async.AsyncClient;
import com.aerospike.client.async.AsyncClientPolicy;
import com.aerospike.client.listener.RecordArrayListener;
import com.aerospike.client.listener.RecordListener;
import com.aerospike.client.policy.Policy;
public class AerospikeAsyncTest {
private static final String NAMESPACE = "default";
private static final String AEROSPIKE_HOST = "<HOST>";
private static final int AEROSPIKE_PORT = 3000;
private static final String PRIMARY_KEY = "<KEY>";
private static final String[] SECONDARY_KEYS = {"<KEY>", "<KEY>",
"<KEY>", "<KEY>", "<KEY>", "<KEY>",
"<KEY>", "<KEY>", "<KEY>", "<KEY>"};
private static class ReadPolicy extends Policy {
public int timeout = 500;
public int maxRetries = 0;
public int sleepBetweenRetries = 0;
}
public static void main(String[] args) throws Exception {
AsyncClientPolicy asyncClientPolicy = new AsyncClientPolicy();
asyncClientPolicy.asyncMaxCommands = 200;
asyncClientPolicy.asyncSelectorThreads = 1;
// NOTE: Un-commenting this timeout setting seems to prevent the bulk call from hanging
//asyncClientPolicy.asyncSelectorTimeout = 2;
// NOTE: Commenting out this thread pool also seems to prevent the bulk call from hanging
asyncClientPolicy.asyncTaskThreadPool = Executors.newFixedThreadPool(10);
AsyncClient client = new AsyncClient(asyncClientPolicy, AEROSPIKE_HOST, AEROSPIKE_PORT);
for (int i = 0; i < 10; i++) {
System.out.println("Running iteration " + i);
// The runExample call will pass sometimes and hang other times
// Seems to be a race condition in the aerospike client library
// When race condition occurs, test will hang when making the bulk get call
new AerospikeAsyncTest().runExample(client);
}
}
private boolean completed;
public void runExample(AsyncClient client) throws Exception {
run(client);
waitTillComplete();
}
private void run(final AsyncClient client) throws AerospikeException {
Key key = new Key(NAMESPACE, (String) null, PRIMARY_KEY);
System.out.println("Running initial get...");
client.get(new ReadPolicy(), new RecordListener() {
public void onSuccess(Key key, final Record record) {
try {
System.out.println("Initial get completed successfully");
Key[] keys = new Key[SECONDARY_KEYS.length];
int i = 0;
for (String secondaryKey : SECONDARY_KEYS) {
keys[i++] = new Key(NAMESPACE, (String) null, secondaryKey);
}
System.out.println("Running bulk get...");
// Client seems to get stuck here, listener is never notified of success or failure when
// race condition occurs
client.get(new ReadPolicy(), new RecordArrayListener() {
@Override
public void onSuccess(final Key[] keys, final Record[] records) {
System.out.println("Bulk get completed successfully: " + records);
notifyCompleted();
}
public void onFailure(AerospikeException e) {
e.printStackTrace();
notifyCompleted();
}
}, keys);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onFailure(AerospikeException e) {
e.printStackTrace();
notifyCompleted();
}
}, key);
}
private synchronized void waitTillComplete() {
while (!completed) {
try {
super.wait();
} catch (InterruptedException ie) {
}
}
}
private synchronized void notifyCompleted() {
completed = true;
super.notify();
}
}
for now there is only com.aerospike.client.Value.BytesValue that store a byte[]. byte[] resides in JVM heap. for cases data create inside the JVM, it doesn't matter. but for many cases such as feeding data from the network, the bytes do not need to go into the JVM heap to be represented as byte[]. The Java app pass the DirectBuffer reference (pointer) to AeroSpike client.
I notice it is using old socket write to outputstream for now
https://github.com/aerospike/aerospike-client-java/blob/master/client/src/com/aerospike/client/cluster/Connection.java
it needs to be changed to use: SocketChannel.write(ByteBuffer src)
why Node class overwrite equals() and hashCode() methods,but in Cluster class use List to store nodes?i think List should be converted to Set.
Hello,
In NodeValidator#validateAlias
method, the Connection
constructor is called and it can throw an AerospikeException.Connection
exception. The connection is closed in the catch block, but only for exceptions thrown inside the try block. Unfortunately, the connection constructor isn't called inside the try
block, so if it throws an exception we will have a connection leak.
I made a pull request that fixes this issue, you can take a look.
#56
We encountered this issue while using aerospike at Thinknear, because we were seeding a host that had a number of aliases, one of them was unreachable and caused that connection leak in our application.
Thanks
The classes LSet, LStack, LMap should be marked as deprecated.
My company is using the Java Aerospike client to connect from our jvm-based apps to various clusters. In an attempt to get good unit test coverage around our applications code, we tried to use Mockito to mock our code interaction with the AerospikeClient class. However since ALL methods of AerospikeClient are final, this is not possible without the use of PowerMockito or some other "more brute force" framework - which usually points out code-smell (IMHO).
So my issue is more of a question as to WHY all of these methods are final?
Thanks in advance...
We are using at out company the asynchronous application framework Vert.x to implement a high-performance web application. We decided to give the AsyncClient a try instead of implementing ourselves the asynchronous calls to Aerospike.
Unfortunately, this didn't work out for us because of a severe bug in the implementation of the AsyncClient, namely its inability to handle failures in one or more of the Aerospike nodes in our cluster. The problem can be reproduced as follows.
There are two Aerospike nodes in our cluster: srvaer01 and srvaer02. The replication factor is 2. We instantiate the AsyncClient like this:
final AsyncClientPolicy clientPolicy = new AsyncClientPolicy();
clientPolicy.failIfNotConnected = true;
final List<Host> hosts = new LinkedList<>();
hosts.add(new Host("srvaer01", 3000));
hosts.add(new Host("srvaer02", 3000));
AsyncClient client = new AsyncClient(clientPolicy, hosts);
We then use the asynchronous methods of the AsyncClient to retrieve data from Aerospike, e.g.:
final Key key = new Key(namespace, storeName, keyName);
client.get(new Policy(), handler, key);
The behavior we observed is the following:
A thread dump of the blocked AsyncClient instance shows the following:
Thread 11346: (state = BLOCKED)
- sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
- java.util.concurrent.locks.LockSupport.park(java.lang.Object) @bci=14, line=175 (Compiled frame)
- java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await() @bci=42, line=2039 (Compiled frame)
- java.util.concurrent.ArrayBlockingQueue.take() @bci=20, line=403 (Interpreted frame)
- com.aerospike.client.async.AsyncCluster$BlockBufferQueue.getByteBuffer() @bci=4, line=114 (Interpreted frame)
- com.aerospike.client.async.AsyncCluster.getByteBuffer() @bci=4, line=68 (Interpreted frame)
- com.aerospike.client.async.AsyncCommand.execute() @bci=38, line=58 (Interpreted frame)
- com.aerospike.client.async.AsyncClient.get(com.aerospike.client.policy.Policy, com.aerospike.client.listener.RecordListener, com.aerospike.client.Key) @bci=28, line=447 (Compiled frame)
...
We were able to reproduce this undesired behavior multiple times. As a workaround to this problem, we changed the AsyncClient with its synchronous counterpart, which works correctly.
Bit of an edge condition and looks like something that should probably be caught closer to aerospike-server but putting it here as we are using the Java client.
When using an LLIST on Aerospike build 3.5.15, issuing the method above with very large values for count causes a SIGSEGV on the server.
(signal.c::160) SIGSEGV received, aborting Aerospike Community Edition build 3.5.15
(signal.c::162) stacktrace: found 17 frames
(signal.c::162) stacktrace: frame 0: /usr/bin/asd(as_sig_handle_segv+0x54) [0x478115]
(signal.c::162) stacktrace: frame 1: /lib/x86_64-linux-gnu/libc.so.6(+0x321e0) [0x7f2088a5c1e0]
(signal.c::162) stacktrace: frame 2: /usr/bin/asd(as_arraylist_insert+0x82) [0x531e6b]
(signal.c::162) stacktrace: frame 3: /usr/bin/asd() [0x52b816]
(signal.c::162) stacktrace: frame 4: /usr/bin/asd() [0x54f798]
(signal.c::162) stacktrace: frame 5: /usr/bin/asd(lua_pcall+0x30) [0x53f440]
(signal.c::162) stacktrace: frame 6: /usr/bin/asd() [0x528491]
(signal.c::162) stacktrace: frame 7: /usr/bin/asd() [0x52940c]
(signal.c::162) stacktrace: frame 8: /usr/bin/asd(udf_apply_record+0x106) [0x4d1dfb]
(signal.c::162) stacktrace: frame 9: /usr/bin/asd(udf_rw_local+0x1a4) [0x4d2101]
(signal.c::162) stacktrace: frame 10: /usr/bin/asd() [0x4bc7bf]
(signal.c::162) stacktrace: frame 11: /usr/bin/asd(as_rw_start+0x28b) [0x4bf503]
(signal.c::162) stacktrace: frame 12: /usr/bin/asd(process_transaction+0xcfd) [0x4c8db0]
(signal.c::162) stacktrace: frame 13: /usr/bin/asd(thr_tsvc_process_or_enqueue+0x3e) [0x4c91f1]
(signal.c::162) stacktrace: frame 14: /usr/bin/asd(thr_demarshal+0x402) [0x48d47d]
(signal.c::162) stacktrace: frame 15: /lib/x86_64-linux-gnu/libpthread.so.0(+0x6b50) [0x7f2089876b50]
(signal.c::162) stacktrace: frame 16: /lib/x86_64-linux-gnu/libc.so.6(clone+0x6d) [0x7f2088b0595d]
This is with a 1GB memory based storage-engine namespace.
I tried upgrading to the latest aerospike client version and had an error trying to use the new register function from within a war.
AerospikeClient.register(readPolicy, contextLoader, resourcePath, name, Language.LUA)
Caused by: java.io.FileNotFoundException: /content/mywar.war/WEB-INF/lib/myjar.jar/udf/list_functions.lua (No such file or directory)
at java.io.FileInputStream.open(Native Method) [rt.jar:1.7.0_71]
Hi,
Suppose one of my aerospike node is down. In that case the java client should be able to reconnect when the node is up.Presently the client keeps the old connection object cached .Please let me know if we can approach to this problem somehow.
Can we have some method in aerospike java client which can provide us all indexes present in all namespaces or in a particular namespace.
I see lib_lmap.lua
contains a function called llist.get_all()
, but I don't see support for that in the LargeMap
class here. Is there a particular reason this has been left out, such as scan()
being better, or would it be possible to get support for it?
No socket.close when there is an exception in https://github.com/aerospike/aerospike-client-java/blob/master/client/src/com/aerospike/client/cluster/Connection.java#L57
Hello,
I'm trying to use increment and get operation like the following:
Record record = client.operate(
null,
new Key("foo", "bar", "keyValue"),
Operation.add(new Bin("test", 1L)),
Operation.get("test")
);
Returned Record contains entry with Integer value type. Everything goes well until Integer overflows.
So after integer overflows like the following:
record = client.operate(
null,
new Key("foo", "bar", "keyValue"),
Operation.add(new Bin("test", Integer.MAX_VALUE)),
Operation.get("test")
);
Returned Record will contain entry with Long value type.
In my opinion it's a little bit confusing and makes me write redundant code in a "switch case" manner.
I think it will be much more better to support the single returned type for such kind of operations.
This lua method is not available in this client, while other clients, like the node.js one, do. We use this method to dynamically generate aggregation functions.
I was able to use this method by previously registering it manually so that Aerospike gets an instance with the method loaded. (This is a hacky way, probably there is a better one):
final LuaInstance instance = LuaCache.getInstance();
instance.registerPackage("load", LuaTable.tableOf(new LuaValue[] {
LuaValue.valueOf("loadLib"), JsePlatform.standardGlobals().get("load") }));
LuaCache.putInstance(instance);
and then in lua
local load = load or loadLib.load
local foo = load("return 'hi'");
info(foo()); -- Prints 'hi'
But this doesn't solve the problem if Aerospike decides it needs more instances than what the pool currently has.
According to the documentation, access control can be applied at the namespace level. On the other hand there is no way AerospikeClient(one instance per cluster), can be created to have different ACL, across namespaces.
Last week I faced the following exception:
java.lang.IllegalArgumentException: Invalid readBytes length: 33554432
.
I used aerospike-helper to fetch some data.
The source of the exception is the following code:
public abstract class MultiCommand extends SyncCommand {
private static final int MAX_BUFFER_SIZE = 1024 * 1024 * 10; // 10 MB
...
protected final void readBytes(int length) throws IOException {
if (length > dataBuffer.length) {
// Corrupted data streams can result in a huge length.
// Do a sanity check here.
if (length > MAX_BUFFER_SIZE) {
throw new IllegalArgumentException("Invalid readBytes length: " + length);
}
dataBuffer = new byte[length];
}
int pos = 0;
while (pos < length) {
int count = bis.read(dataBuffer, pos, length - pos);
if (count < 0) {
throw new EOFException();
}
pos += count;
}
dataOffset += length;
}
...
}
According to the comment, data might be corrupted. But then I removed this limit and my data was successfully deserialized. Nothing was corrupted at all.
So I am wondering, is there any reason for this restriction? Or maybe it is some sort of legacy code?
As far as I know C client does not contain this limit. Could it be just removed for java client?
Trying to use the client for the first time. Already I got bitten by the checked exception that is AerospikeException.
nearly everyone agrees today that checked exceptions in Java were a bad idea and all new libraries try to avoid.
All this will do is force us to do the same code over and over again:
try {
return new AerospikeClient(config.getHost(),config.getPort());
} catch (AerospikeException e) {
throw new RuntimeException(e);
}
We had to deal with the same issues when using Astyanax Cassandra client and it was really annoying.
Please consider changing all your exceptions to be regular unchecked runtime exceptions/
Not sure if its an issue or intended but removeUdf method in the API is missing. I'm currently using a self-made tool to generate lua UDFs and register them in Aerospike, but I cannot remove them in a "development way" unless I do it manually.
This operation already exists in Ruby and Go clients and I think it is odd to have inconsistency for different language bindings (http://www.aerospike.com/docs/client/go/usage/udf/remove.html and http://www.aerospike.com/docs/client/ruby/usage/udf/remove.html) even more given the fact I can register indexes and UDFs but cannot remove them.
EDIT: C bindings also have remove options http://www.aerospike.com/docs/client/c/usage/udf/register.html
Calling LargeList.add(Value value) with a byte array Value throws an exception:
Example Call:
list.add(Value.get("testhello".getBytes())
Exception:
AerospikeException: Error Code 100: /opt/aerospike/sys/udf/lua/ldt/lib_llist.lua:1243: bad argument #2 to '?' (number expected, got string) (ReadCommand.java:142)
[error] com.aerospike.client.command.ReadCommand.handleUdfError(ReadCommand.java:142)
[error] com.aerospike.client.command.ReadCommand.parseResult(ReadCommand.java:106)
[error] com.aerospike.client.command.SyncCommand.execute(SyncCommand.java:56)
[error] com.aerospike.client.AerospikeClient.execute(AerospikeClient.java:926)
This is the exists method. When corresponding key or llist is missing in Aerospike, list object at the 2nd line is null & hence list.size() at 3rd line throws Null Pointer exception.
public List<Boolean> exists(List<Value> keyValues) throws AerospikeException {
List<?> list = (List<?>)client.execute(policy, key, PackageName, "exists", binName, Value.get(keyValues));
List<Boolean> target = new ArrayList<Boolean>(list.size());
for (Object obj : list) {
target.add(Util.toBoolean(obj));
}
return target;
}
Not sure if similar issues are there for other methods too.
I looked at the Batch example:
and it seems to do individual writes.
It is not clear from the docs or the examples how to do large batch saves (e.g. update 5000 different records in a single call, instead of 5000 separate saves).
It is possible to update different sets in the same batch?
E.g. save 5000 records in one set, plus an audit trail record for each of them in a separate set, as part of the same operation?
I am trying to write unit tests for some code of mine which is calling AerospikeClient.queryAggregate
. I have mocked the AerospikeClient
via the IAerospikeClient
interface using Mockito. So far, so good.
Where I run into trouble is that I cannot mock the result. Mockito cannot mock ResultSet
because that class is final. Its dependency, QueryAggregateExecutor
is also final, which would lead me to mock Cluster
. That is possible, but leads down a very complicated rabbit hole.
RecordSet
might be more practical to mock since it depends on a QueryExecutor
, which is the abstract parent class. However, many of QueryExecutor
's method are final, so it may still be difficult.
I think the most expedient solution would be to make RecordSet
and ResultSet
non-final. I understand making classes final is good practice, but I believe making the code mock-able so it can be unit tested is considerably more valuable. I am certainly open to other suggestions.
By the way, the ExecutionTask
returned from AerospikeClient.execute
has a similar problem, so you may wish to apply the same solution. I was able to work around that case like so:
ExecuteTask task = client.execute(...); // When client is a mock, will return null
if (task != null) task.waitTillComplete();
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.