Java memcache Client 資料操作源碼剖析

來源:互聯網
上載者:User

標籤:



在學習使用Java_Memcache操作memcache後,饒有興趣的研究了一下Java_Memcache的源碼。Java_Memcache在類AscIIClient中封裝了資料操作方法set/add/delete/append/get等。

儲存資料set

由Memcache命令詳解,我們知道memcache原始的set命令格式為

set <key> <flag> <expiretime> <bytes> \r\n

<value> \r\n

而在Java_Memcache中set操作資料最始調用的是set(String, String, Object, Date, Integer, Long, flag)方法。



private boolean set(String s, String s1, Object obj, Date date, Integer integer, Long long1, boolean flag){    SchoonerSockIO schoonersockio;    int i;    String s2;    ......    s1 = sanitizeKey(s1);    ......    schoonersockio = pool.getSock(s1, integer);    if(schoonersockio == null)    {        if(errorHandler != null)            errorHandler.handleErrorOnSet(this, new IOException("no socket to server available"), s1);        return false;    }    if(date == null)        date = new Date(0L);    i = NativeHandler.getMarkerFlag(obj);    s2 = s + " " + s1 + " " + i + " " + date.getTime() / 1000L + " ";    boolean flag1;    schoonersockio.writeBuf.clear();    schoonersockio.writeBuf.put(s2.getBytes());    int j = schoonersockio.writeBuf.position();    schoonersockio.writeBuf.put(BLAND_DATA_SIZE);    if(long1.longValue() != 0L)        schoonersockio.writeBuf.put((new StringBuilder()).append(" ").append(long1.toString()).toString().getBytes());    schoonersockio.writeBuf.put(B_RETURN);    SockOutputStream sockoutputstream = new SockOutputStream(schoonersockio);    int k = 0;    if(i != 0)    {        byte abyte0[];        if(flag)            abyte0 = obj.toString().getBytes(defaultEncoding);        else            abyte0 = NativeHandler.encode(obj);        sockoutputstream.write(abyte0);        k = abyte0.length;    } else    {        k = transCoder.encode(sockoutputstream, obj);    }    schoonersockio.writeBuf.put(B_RETURN);    byte abyte1[] = (new Integer(k)).toString().getBytes();    int l = schoonersockio.writeBuf.position();    schoonersockio.writeBuf.position(j);    schoonersockio.writeBuf.put(abyte1);    schoonersockio.writeBuf.position(l);    schoonersockio.flush();    String s3 = (new SockInputStream(schoonersockio, 2147483647)).getLine();    if(!"STORED\r\n".equals(s3))        break MISSING_BLOCK_LABEL_538;    ......    return false;}

    當我們使用MemCacheClient.set(“name”,”abcdef”),通過對比上面的code,首先i=NativeHandler.getMarkerFlag(“abcdef”)值為32, 然後拼接字串s2=”set name 32 0 ”並將s2放入ByteBuffer中,然後調用schoonersockio.writeBuf.put(BLAND_DATA_SIZE),而BLADN_DATA_SIZE是"       ".getBytes(),其實就是“set name 32 0        ”,最後schoonersockio.writeBuf.put(B_RETURN)即輸入\r\n,最後再通過transCoder.encode()將value寫入。

public void encode(OutputStream outputstream, Object obj)throws IOException{    ObjectOutputStream objectoutputstream = new ObjectOutputStream(outputstream);    objectoutputstream.writeObject(obj);    objectoutputstream.close();}

    其實就是將對象序列化,因此在使用Java_Memcache操作的自訂對象必須都實現Serializable介面。

但是,如果我們直接運行”set name 32 0       \r\n“會提示錯誤資訊。

我很困惑set命令最後的<byte>參數是如何處理的????

反編譯後的代碼不全 or 反編譯有誤?

資料提取get

同樣,memcache原始的get命令很簡單,其基本格式為:

get <key> \r\n

而在Java_Memcache中,AscIIClient中是按如下處理的:

public Object get(String s){    return get(s, null);}public Object get(String s, Integer integer){    return get("get", s, integer, false);}
private Object get(String s, String s1, Integer integer, boolean flag){    SchoonerSockIO schoonersockio;    String s2;    ....         s1 = sanitizeKey(s1);    schoonersockio = pool.getSock(s1, integer);    s2 = (new StringBuilder()).append(s).append(" ").append(s1).toString();    int i;    int j;    SockInputStream sockinputstream;    boolean flag1;    StringBuffer stringbuffer;    int l;    schoonersockio.writeBuf.clear();    schoonersockio.writeBuf.put(s2.getBytes());    schoonersockio.writeBuf.put(B_RETURN);    schoonersockio.flush();    i = 0;    j = 0;    sockinputstream = new SockInputStream(schoonersockio, 2147483647);    flag1 = false;    stringbuffer = new StringBuffer();    l = 0;    <span style="color:#006600;">//前面一部分就是構建字串 “get name \r\n”,即向Memcache server發出get命令</span>_L5:    int k;    if(flag1)        break MISSING_BLOCK_LABEL_365;    k = sockinputstream.read();    if(k != 32 && k != 13)        break MISSING_BLOCK_LABEL_353;    <span style="color:#006600;">//一直讀取到斷行符號或換行</span>    l;    JVM INSTR tableswitch 0 3: default 322    goto _L1 _L2 _L1 _L3 _L4    <span style="color:#006600;">//這裡是一個while迴圈接收從memcache server返回的訊息字元</span>_L1:    break; /* Loop/switch isn't completed */_L2:    Object obj;    if(!"END\r\n".startsWith(stringbuffer.toString()))        break; /* Loop/switch isn't completed */    <span style="color:#006600;">//如果不是END\r\r行,就繼續處理,否則就直接返回空</span>    obj = null;    if(schoonersockio != null)    {        schoonersockio.close();        schoonersockio = null;    }    return obj;    <span style="color:#006600;">//這裡處理在memcache中沒有對應key值時取不到任何值,調用get命令後直接得到END/r/n,返回空</span>_L3:    j = Integer.parseInt(stringbuffer.toString());    break; /* Loop/switch isn't completed */_L4:    i = Integer.parseInt(stringbuffer.toString());    l++;    stringbuffer = new StringBuffer();    if(k == 13)    {        sockinputstream.read();        flag1 = true;    }    goto _L5    stringbuffer.append((char)k);    goto _L5    Object obj3;    Object obj1 = null;    sockinputstream.willRead(i);    if(i > 0)        if(NativeHandler.isHandled(j))        {            byte abyte0[] = sockinputstream.getBuffer();            if((j & 2) == 2)            {                GZIPInputStream gzipinputstream = new GZIPInputStream(new ByteArrayInputStream(abyte0));                ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(abyte0.length);                byte abyte1[] = new byte[2048];                int i1;                while((i1 = gzipinputstream.read(abyte1)) != -1)                     bytearrayoutputstream.write(abyte1, 0, i1);                abyte0 = bytearrayoutputstream.toByteArray();                <span style="color:#006600;">//讀取資料到位元組數組中</span>                gzipinputstream.close();            }            if(primitiveAsString || flag)                obj1 = new String(abyte0, defaultEncoding);            else                obj1 = NativeHandler.decode(abyte0, j);                <span style="color:#006600;">//最後調用decodeString解碼字串</span>             }          else            if(transCoder != null)            {                Object obj2 = sockinputstream;                if((j & 2) == 2)                    obj2 = new GZIPInputStream(((java.io.InputStream) (obj2)));                if(classLoader == null)                    obj1 = transCoder.decode(((java.io.InputStream) (obj2)));                else                    obj1 = ((ObjectTransCoder)transCoder).decode(((java.io.InputStream) (obj2)), classLoader);         }    sockinputstream.willRead(2147483647);    sockinputstream.getLine();    sockinputstream.getLine();    obj3 = obj1;    if(schoonersockio != null)    {        schoonersockio.close();        schoonersockio = null;    }    return obj3;}

我們可以對比直接使用memcache命令操作的輸入輸出來理解,就是在輸入完get命令後解析字元序列,編碼成實際的data。



使用反編譯後的代碼可能理解起來比較困難,我們可以查看Java_Memcache client原始代碼,學習起來更省心。

    有些版本原代碼是在MemcacheClient中直接get/set data的。

https://code.csdn.net/dwzteam/dwz_springmvc/tree/f744cf61e31188e93c31644686a07ece5b84e1e4/src/dwz/cache/memcache/client/MemcachedClient.java

這份程式碼分析Memcache處理資料會更加簡單。

總結

至此,我們介紹了如何在windows安裝並操作Memcache,分析了Memcache分布式原理,探討了一般Hash演算法和一致性Hash演算法,如何操作資料。我們從整體上對Java_Memcache Client有了深刻的認識,其主要思想就是維護一套分布式Server的資訊,對每台Server維護其Socket串連,根據操作的資料進行Hash映射到某台Server上,最後構建memcache命令操作和解析資料。

    相信在掌握Java_Memcache_Client的思想和實現過程後,您會使用得更加得心應手。

Windows環境下的Memcache實戰  http://blog.csdn.net/musa875643dn/article/details/45439417 

Memcache命令詳解       http://blog.csdn.net/musa875643dn/article/details/45935895

Memcache分布式原理解析 http://blog.csdn.net/musa875643dn/article/details/45675711

Memcache Hash演算法揭秘  http://blog.csdn.net/musa875643dn/article/details/45796887


Java memcache Client 資料操作源碼剖析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.