ZoroXing / xmemcached

Automatically exported from code.google.com/p/xmemcached
Apache License 2.0
0 stars 0 forks source link

Counter的问题,请确认是否为BUG #142

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
//可以使用counter来替代上面的方法
[code]
Counter counter=client.getCounter("counter",6);
counter.get();  //
counter.incrementAndGet();
counter.decrementAndGet();
counter.addAndGet(-7);
System.out.println("counter:"+counter.get());
client.delete("counter");
[/code]

经过测试,必须要要先调用一次get(代码第二行),后面的结果
才会正确,不知道是不是BUG。

Original issue reported on code.google.com by solosky...@gmail.com on 21 Jul 2011 at 8:08

GoogleCodeExporter commented 8 years ago
你期望什么结果呢?

Original comment by killme2...@gmail.com on 21 Jul 2011 at 8:19

GoogleCodeExporter commented 8 years ago
无论有没有get这一行,结果都应当是0,我不知道你测试出来�
��结果是什么?你用的memcached是官方提供跑在linux或者mac上的�
��?

Original comment by killme2...@gmail.com on 21 Jul 2011 at 11:44

GoogleCodeExporter commented 8 years ago

试试这个,把下面的第5行的-7改成2然后在试试。之前由于有�
��和没错都变成0了,不好区别。
[code]
Counter counter=client.getCounter("counter",6);
counter.get();  //
counter.incrementAndGet();
counter.decrementAndGet();
counter.addAndGet(2);
System.out.println("counter:"+counter.get());
client.delete("counter");
[/code]

我已经下班了,环境和代码在公司,我现在不方便测试,不��
�还记得之前的结果,我还认真的抓了包分析,发现如果注释�
��第二行的代码,第三行的代码貌似没有任何效果,在抓包中
也没有看到这个请求,后面的代码都是正确的。
如果注释掉,结果是7,如果不注释掉,结果就是8,我记得当
时我反复测试的确是这个结果。Mem的版本是1.4.x 
后面小版本号记不住了。明天回公司在看看。

你先测试下,如果结果不是我说的那样,我明天回到公司再��
�试。

Original comment by solosky...@gmail.com on 21 Jul 2011 at 12:18

GoogleCodeExporter commented 8 years ago
正确结果应当为7

这是个bug,主要是在get方法里多了个副作用,当key不存在的��
�候主动add了一次,这是多余的。导致结果会为8。

感谢你的报告,我会修正下。

Original comment by killme2...@gmail.com on 21 Jul 2011 at 1:04

GoogleCodeExporter commented 8 years ago
不客气,但为什么正确的结果是7呢,应该是8吧~

[code]
Counter counter=client.getCounter("counter",6);
counter.get();  //
counter.incrementAndGet(); //counter=7
counter.decrementAndGet(); //counter=6
counter.addAndGet(2);//counter=8
System.out.println("counter:"+counter.get()); //counter=8
client.delete("counter");
[/code]

Original comment by *rongqia...@chuntent.com on 21 Jul 2011 at 1:12

GoogleCodeExporter commented 8 years ago
incrementAndGet或者decrementAndGet在key不存在的时候,会调用add将��
�始值放入,但是不会递增。

Counter的初始值是指当key不存在的时候将该值设置为初始值,�
��次操作不起作用的。

Original comment by killme2...@gmail.com on 21 Jul 2011 at 1:20

GoogleCodeExporter commented 8 years ago
incrementAndGet/incrementAndGet本意是递增或者减少值,API的名字代�
��的含义是明确的,你说“会在key不存在的时候,会调用add将
初始值放入,但是不会递增”,这明显存在二义性,调用这��
�API的行为不明确,这样会造成很不容易调试的错误。

强烈建议将这两个API的行为修改为“在key不存在的时候,会��
�用add将初始值放入,然后执行递增或者递减的操作”,或者�
��在构造Counter的时候检测值是否存在,如果不存在就初始化��
�。

Original comment by solosky...@gmail.com on 22 Jul 2011 at 1:38

GoogleCodeExporter commented 8 years ago
嗯,这是欠考虑的地方,不符合直觉。
但是现在修改可能会破坏已有的代码,我考虑下吧。

Original comment by killme2...@gmail.com on 22 Jul 2011 at 1:41

GoogleCodeExporter commented 8 years ago
另外关于CAS建议封装如下的API,可以更加方便的进行CAS操作��
�

        /**
     * 封装对CASOpertion的操作,可以指定最大的尝试次数
     * @param key           需更新缓存的KEY
     * @param value         待更新的缓存的值
     * @param maxRetryTimes 最大重试次数
     * @return  如果在最大尝试次数内更新成功返回true,否则返回false
     */
    public <T> boolean casOperation(String key, final T value, final int maxRetryTimes)
    {
        return this.cas(key, 0, new CASOperation<T>() {
            @Override
            public int getMaxTries() {
                return maxRetryTimes;
            }
            @Override
            public T getNewValue(long currentCAS, T currentValue) {
                return value;
            }
        });
    }

Original comment by solosky...@gmail.com on 22 Jul 2011 at 1:52

GoogleCodeExporter commented 8 years ago
再废话一点,昨天测试的时候发现很客户端很多地方都没有��
�测服务器返回的值是不是ERROR,比如下面的代码
[code]
client.set("good_value", 3000, 
"abc"); //不能这样初始化值然后原子递增或递减,否则结果是�
��误
client.incr("good_value", 2, 0);
[/code]
将会抛出下面的异常:
java.lang.NumberFormatException: For input string: "CLIENT_ERROR cannot 
increment or decrement non-numeric value"
    at java.lang.NumberFormatException.forInputString(Unknown Source)
    at java.lang.Long.parseLong(Unknown Source)
    at java.lang.Long.valueOf(Unknown Source)
    at net.rubyeye.xmemcached.command.text.TextIncrDecrCommand.decode(TextIncrDecrCommand.java:75)
    at net.rubyeye.xmemcached.codec.MemcachedDecoder.decode0(MemcachedDecoder.java:59)
    at net.rubyeye.xmemcached.codec.MemcachedDecoder.decode(MemcachedDecoder.java:54)
    at com.google.code.yanf4j.nio.impl.NioTCPSession.decode(NioTCPSession.java:288)
    at com.google.code.yanf4j.nio.impl.NioTCPSession.readFromBuffer(NioTCPSession.java:205)
    at com.google.code.yanf4j.nio.impl.AbstractNioSession.onRead(AbstractNioSession.java:198)
    at com.google.code.yanf4j.nio.impl.AbstractNioSession.onEvent(AbstractNioSession.java:343)
    at com.google.code.yanf4j.nio.impl.SocketChannelController.dispatchReadEvent(SocketChannelController.java:56)
    at com.google.code.yanf4j.nio.impl.NioController.onRead(NioController.java:157)
    at com.google.code.yanf4j.nio.impl.Reactor.dispatchEvent(Reactor.java:294)
    at com.google.code.yanf4j.nio.impl.Reactor.run(Reactor.java:141)

明显是没有检测返回值嘛,希望能完善下。

Original comment by solosky...@gmail.com on 22 Jul 2011 at 2:29

GoogleCodeExporter commented 8 years ago
很多地方应该不至于,我看了下,这个地方确实没检查,感��
�你的报告。

新加api是不准备加入了,你可以自己封装。

Original comment by killme2...@gmail.com on 22 Jul 2011 at 2:49

GoogleCodeExporter commented 8 years ago
        /**
     * 封装对CASOpertion的操作,可以指定最大的尝试次数
     * @param key           需更新缓存的KEY
     * @param value         待更新的缓存的值
     * @param maxRetryTimes 最大重试次数
     * @return  如果在最大尝试次数内更新成功返回true,否则返回false
     */
    public <T> boolean casOperation(String key, final T value, final int maxRetryTimes)

我自己还在外边包装了一个重试时间的设置参数,通常操作��
�败都是因为当时网络不稳定,不断重试意义不大,还不如增�
��一个短暂的等待时间再重试。

Original comment by springda...@gmail.com on 4 Aug 2011 at 12:53

GoogleCodeExporter commented 8 years ago
Fixed by 

https://github.com/killme2008/xmemcached/commit/979eb04d9fcc1a1fcbb2ff39782ea158
1ca646c5

Original comment by killme2...@gmail.com on 5 Sep 2011 at 1:24