javamemcachedxmemcached

xmemcached set error ArrayIndexOutOfBounds


I add to servers to xmemcached and try to set a few items. I get this exception

bar
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at java.util.ArrayList.elementData(ArrayList.java:371)
at java.util.ArrayList.get(ArrayList.java:384)
at net.rubyeye.xmemcached.impl.ArrayMemcachedSessionLocator.getSessionByKey(ArrayMemcachedSessionLocator.java:67)
at net.rubyeye.xmemcached.impl.MemcachedConnector.findSessionByKey(MemcachedConnector.java:570)
at net.rubyeye.xmemcached.impl.MemcachedConnector.send(MemcachedConnector.java:487)
at net.rubyeye.xmemcached.XMemcachedClient.sendCommand(XMemcachedClient.java:288)
at net.rubyeye.xmemcached.XMemcachedClient.fetch0(XMemcachedClient.java:617)
at net.rubyeye.xmemcached.XMemcachedClient.get0(XMemcachedClient.java:1030)
at net.rubyeye.xmemcached.XMemcachedClient.get(XMemcachedClient.java:988)
at net.rubyeye.xmemcached.XMemcachedClient.get(XMemcachedClient.java:999)
at net.rubyeye.xmemcached.XMemcachedClient.get(XMemcachedClient.java:1021)
at AxCacheEngine.Libs.AxMemcached.main(AxMemcached.java:33)

Here's the code:

MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses(
            "127.0.0.1:11211 127.0.0.1:11311"
    ));
builder.setSessionLocator(new ArrayMemcachedSessionLocator(HashAlgorithm.ONE_AT_A_TIME));

MemcachedClient memcachedClient = builder.build();
System.out.println("Trying to get 1 milllion items");

int hugeItems = 0;
int normalItems = 0;
int totalCount = 0;

System.out.println(memcachedClient.set("foo",0,"bar"));
System.out.println(memcachedClient.set("bar",0,"baz"));
System.out.println(memcachedClient.set("yin",0,"yang"));

What could be the problem? Is there some issue with distribution strategy? I get this error when I try to get the items set from php-memcached. Please help


Solution

  • I replicated your issue and I think that you cannot use the ArrayMemcachedSessionAllocator with the One at a Time hashing algorithm for 2 or more sessions.

    According to the documentation the ArrayMemcachedSessionAllocator class locates Sessions as hash(key) mod sessions.size().

    And this number will be an index of an Arraylist in the code. In particular, this is the guilty line:

    long start = this.getHash(size, key); //gets computed by ONE_AT_A_TIME hash % number of sessions
    List<Session> sessions = sessionList.get((int) start); //this is where you get out of bounds
    

    The problem is that ONE_AT_A_TIME hash can be negative. It is negative for bar (the source of the problem).

    So if you have a negative hash value modulo 2 (number of servers), start is a negative value too.

    On the other hand, foo has a positive hash value for One_At_a_Time and modulo 2 remains a positive value!

    Note: The algorithm works perfectly fine if you have one server (as any number % 1 is positive).

    So, I think you just can't use this hashing algorithm with the ArrayMemcachedSessionAllocator class for 2 or more servers.