shixin42 / spymemcached

Automatically exported from code.google.com/p/spymemcached
0 stars 0 forks source link

CAS operation fails due to client sign-extending the CAS value #209

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
2.7.1, binary protocol

Our memcached cluster is returning large values for cas such that bit 31 is 
set...I'm not sure why our cas values are so large...they are large even for 
newly created keys.

This seems to be triggering a bug in spymemcached where the cas gets 
sign-extended on the subsequent request.

The result is that all cas operations fail with CASResponse.EXISTS.  

The relevant code is:

CASValue<Object> casv = mc.gets("xx_test_yy");

CASResponse r = mc.cas("xx_test_yy", casv.getCas(), (14*60*60), new 
Long(0xBEEF), mc.getTranscoder());
if (r == CASResponse.EXISTS) {
    System.out.println("cas failed: exists");
}

Wireshark trace of binary protocol:

00000000  80 0a 00 00 00 00 00 00  00 00 00 00 00 00 00 03 ........ ........
00000010  00 00 00 00 00 00 00 00                          ........ 
    00000000  81 0a 00 00 00 00 00 00  00 00 00 00 00 00 00 03 ........ ........
    00000010  00 00 00 00 00 00 00 00                          ........ 
00000018  80 00 00 0a 00 00 00 00  00 00 00 0a 00 00 00 05 ........ ........
00000028  00 00 00 00 00 00 00 00  78 78 5f 74 65 73 74 5f ........ xx_test_
00000038  79 79                                            yy
    00000018  81 00 00 00 04 00 00 00  00 00 00 07 00 00 00 05 ........ ........
    00000028  00 00 00 00 9a c5 7c 35  00 00 03 00 ab ca bc    ......|5 .......
0000003A  80 01 00 0a 08 00 00 00  00 00 00 14 00 00 00 06 ........ ........
0000004A  ff ff ff ff 9a c5 7c 35  00 00 03 00 00 00 c4 e0 ......|5 ........
0000005A  78 78 5f 74 65 73 74 5f  79 79 be ef             xx_test_ yy..
    00000037  81 01 00 00 00 00 00 02  00 00 00 14 00 00 00 06 ........ ........
    00000047  00 00 00 00 00 00 00 00  44 61 74 61 20 65 78 69 ........ Data exi
    00000057  73 74 73 20 66 6f 72 20  6b 65 79 2e             sts for  key.

The gets returns a cas value of 0x9AC57C35, but this is sign extended on the 
subsequent cas call.

I believe the bug to be here:

    static long decodeLong(byte[] data, int i) {
        return(data[i  ] & 0xff) << 56
            | (data[i+1] & 0xff) << 48
            | (data[i+2] & 0xff) << 40
            | (data[i+3] & 0xff) << 32
            | (data[i+4] & 0xff) << 24
            | (data[i+5] & 0xff) << 16
            | (data[i+6] & 0xff) << 8
            | (data[i+7] & 0xff);
    }

These operations are done as integer operations cast to a long only on return, 
thus if you run this on 0x000000009ac57c35 you get sign extension.

One possible fix is this:

    static long decodeLong(byte[] data, int i) {
        return (long)(data[i  ] & 0xff) << 56
        | (long)(data[i+1] & 0xff) << 48
        | (long)(data[i+2] & 0xff) << 40
        | (long)(data[i+3] & 0xff) << 32
        | (long)(data[i+4] & 0xff) << 24
        | (long)(data[i+5] & 0xff) << 16
        | (long)(data[i+6] & 0xff) << 8
        | (long)(data[i+7] & 0xff);
    }

Original issue reported on code.google.com by bkin...@gmail.com on 3 Oct 2011 at 6:29

GoogleCodeExporter commented 8 years ago
This is a duplicate issue. There is a fix that has already been checked into 
both the 2.7.2 and 2.8 branches. 

See: http://code.google.com/p/spymemcached/issues/detail?id=202

Original comment by mikewie...@gmail.com on 4 Oct 2011 at 5:42