Changeset 14:8b4b6177d6a2

Show
Ignore:
Timestamp:
04/01/08 15:16:49 (5 months ago)
Author:
ryan@…
Message:

Added: cas/gets, and noreply option on sets

Files:
7 modified

Legend:

Unmodified
Added
Removed
  • jmemcached-cli/src/main/java/com/thimbleware/jmemcached/Main.java

    r10 r14  
    126126        // create daemon and start it 
    127127        MemCacheDaemon daemon = new MemCacheDaemon(); 
    128         LRUCacheStorageDelegate cacheStorage = new LRUCacheStorageDelegate(max_size, max_size, 1024000); 
     128        LRUCacheStorageDelegate cacheStorage = new LRUCacheStorageDelegate(max_size, maxBytes, 1024000); 
    129129        daemon.setCache(new Cache(cacheStorage)); 
    130130        daemon.setAddr(addr); 
  • jmemcached-core/src/main/java/com/thimbleware/jmemcached/Cache.java

    r10 r14  
    3232    public int getMisses; 
    3333 
     34    public long casCounter; 
     35 
    3436    protected CacheStorage cacheStorage; 
     37 
     38 
     39    public enum StoreResponse { 
     40        STORED, NOT_STORED, EXISTS, NOT_FOUND 
     41    } 
    3542 
    3643 
     
    4047     */ 
    4148    private final ReadWriteLock cacheReadWriteLock; 
    42  
    4349 
    4450    /** 
     
    9096     * @return the message response string 
    9197     */ 
    92     protected boolean add(MCElement e) { 
    93         try { 
    94             startCacheRead(); 
    95             return !is_there(e.keystring) && set(e); 
     98    protected StoreResponse add(MCElement e) { 
     99        try { 
     100            startCacheRead(); 
     101            if (is_there(e.keystring)) return set(e); 
     102            else return StoreResponse.NOT_STORED; 
    96103        } finally { 
    97104            finishCacheRead(); 
     
    105112     * @return the message response string 
    106113     */ 
    107     public boolean replace(MCElement e) { 
    108         try { 
    109             startCacheRead(); 
    110             return is_there(e.keystring) && set(e); 
    111         } finally { 
    112             finishCacheRead(); 
    113         } 
    114     } 
     114    public StoreResponse replace(MCElement e) { 
     115        try { 
     116            startCacheRead(); 
     117            if (is_there(e.keystring)) return set(e); 
     118            else return StoreResponse.NOT_STORED; 
     119        } finally { 
     120            finishCacheRead(); 
     121        } 
     122    } 
     123 
    115124 
    116125    /** 
     
    120129     * @return the message response string 
    121130     */ 
    122     protected boolean set(MCElement e) { 
     131    protected StoreResponse set(MCElement e) { 
    123132        try { 
    124133            startCacheWrite(); 
    125134            setCmds += 1;//update stats 
     135 
     136            // increment the CAS counter; put in the new CAS 
     137            e.cas_unique = casCounter++; 
     138 
    126139            this.cacheStorage.put(e.keystring, e); 
    127             return true; 
     140            return StoreResponse.STORED; 
     141        } finally { 
     142            finishCacheWrite(); 
     143        } 
     144    } 
     145 
     146    public StoreResponse cas(Long cas_key, MCElement e) { 
     147        try { 
     148            startCacheWrite(); 
     149            // have to get the element 
     150            MCElement element = get(e.keystring); 
     151            if (element == null) 
     152                return StoreResponse.NOT_FOUND; 
     153 
     154            if (element.cas_unique == cas_key) { 
     155                // cas_unique matches, now set the element 
     156                return set(e); 
     157            } else { 
     158                // cas didn't match; someone else beat us to it 
     159                return StoreResponse.EXISTS; 
     160            } 
     161 
    128162        } finally { 
    129163            finishCacheWrite(); 
     
    157191            e.data = valueOf(old_val).getBytes(); // toString 
    158192            e.data_length = e.data.length; 
     193 
     194            // assign new cas id 
     195            e.cas_unique = casCounter++; 
     196 
    159197            this.cacheStorage.put(e.keystring, e); // save new value 
    160198            return old_val; 
     
    345383        return getMisses; 
    346384    } 
     385 
    347386} 
  • jmemcached-core/src/main/java/com/thimbleware/jmemcached/CommandDecoder.java

    r10 r14  
    178178        if (cmd.cmd == Commands.ADD || 
    179179                cmd.cmd == Commands.SET || 
    180                 cmd.cmd == Commands.REPLACE) { 
     180                cmd.cmd == Commands.REPLACE || 
     181                cmd.cmd == Commands.CAS) { 
    181182 
    182183            // if we don't have all the parts, it's malformed 
    183             if (parts.size() != 5) { 
     184            if (parts.size() < 5) { 
    184185                return new SessionStatus(ERROR); 
    185186            } 
     187 
    186188 
    187189            int size = Integer.parseInt(parts.get(4)); 
     
    196198            cmd.element.data_length = size; 
    197199 
     200            // look for cas and "noreply" elements 
     201            if (parts.size() > 5) { 
     202                int noreply = cmd.cmd == Commands.CAS ? 6 : 5; 
     203                if (cmd.cmd == Commands.CAS) { 
     204                    cmd.cas_key = Long.valueOf(parts.get(5)); 
     205                } 
     206 
     207                if (parts.size() == noreply + 1 && parts.get(noreply).equalsIgnoreCase("noreply")) 
     208                    cmd.noreply = true; 
     209 
     210            } 
     211 
    198212            return new SessionStatus(WAITING_FOR_DATA, size, cmd); 
    199213 
    200214        } else if (cmd.cmd == Commands.GET || 
     215                cmd.cmd == Commands.GETS || 
    201216                cmd.cmd == Commands.INCR || 
    202217                cmd.cmd == Commands.DECR || 
  • jmemcached-core/src/main/java/com/thimbleware/jmemcached/CommandMessage.java

    r10 r14  
    2626    public MCElement element; 
    2727    public ArrayList<String> keys; 
     28    public boolean noreply; 
     29    public Long cas_key; 
    2830 
    2931    public CommandMessage(String cmd) { 
  • jmemcached-core/src/main/java/com/thimbleware/jmemcached/Commands.java

    r10 r14  
    2020public interface Commands { 
    2121    String GET = "GET".intern(); 
     22    String GETS = "GETS".intern(); 
    2223    String DELETE = "DELETE".intern(); 
    2324    String DECR = "DECR".intern(); 
     
    2627    String ADD = "ADD".intern(); 
    2728    String SET = "SET".intern(); 
     29    String CAS = "CAS".intern(); 
    2830    String STATS = "STATS".intern(); 
    2931    String VERSION = "VERSION".intern(); 
  • jmemcached-core/src/main/java/com/thimbleware/jmemcached/MCElement.java

    r10 r14  
    2727    public byte[] data; 
    2828    public String keystring; 
     29    public long cas_unique; 
    2930} 
  • jmemcached-core/src/main/java/com/thimbleware/jmemcached/ServerSessionHandler.java

    r10 r14  
    2222import org.slf4j.LoggerFactory; 
    2323 
     24import static java.lang.Integer.parseInt; 
     25import static java.lang.String.valueOf; 
    2426import java.nio.charset.CharacterCodingException; 
    2527import java.nio.charset.Charset; 
    2628import java.nio.charset.CharsetEncoder; 
    2729import java.util.Iterator; 
    28 import static java.lang.String.valueOf; 
    29 import static java.lang.Integer.*; 
    3030 
    3131/** 
     
    5050    public boolean verbose; 
    5151 
    52     public static CharsetEncoder ENCODER  = Charset.forName("US-ASCII").newEncoder(); 
     52    public static CharsetEncoder ENCODER = Charset.forName("US-ASCII").newEncoder(); 
    5353 
    5454    /** 
     
    5959     * Construct the server session handler 
    6060     * 
    61      * @param cache the cache to use 
     61     * @param cache            the cache to use 
    6262     * @param memcachedVersion the version string to return to clients 
    63      * @param verbosity verbosity level for debugging 
    64      * @param idle how long sessions can be idle for 
     63     * @param verbosity        verbosity level for debugging 
     64     * @param idle             how long sessions can be idle for 
    6565     */ 
    6666    public ServerSessionHandler(Cache cache, String memcachedVersion, boolean verbosity, int idle) { 
     
    6868 
    6969        this.cache = cache; 
    70          
     70 
    7171        started = Now(); 
    7272        version = memcachedVersion; 
     
    141141 
    142142        ResponseMessage r = new ResponseMessage(); 
    143         if (cmd == Commands.GET) { 
     143        if (cmd == Commands.GET || cmd == Commands.GETS) { 
    144144            for (int i = 0; i < cmdKeysSize; i++) { 
    145145                MCElement result = get(command.keys.get(i)); 
    146146                if (result != null) { 
    147                     r.out.putString("VALUE " + result.keystring + " " + result.flags + " " + result.data_length + "\r\n", ENCODER); 
     147                    r.out.putString("VALUE " + result.keystring + " " + result.flags + " " + result.data_length + (cmd == Commands.GETS ? " " + result.cas_unique : "") + "\r\n", ENCODER); 
    148148                    r.out.put(result.data, 0, result.data_length); 
    149149                    r.out.putString("\r\n", ENCODER); 
     
    153153            r.out.putString("END\r\n", ENCODER); 
    154154        } else if (cmd == Commands.SET) { 
    155             r.out.putString(set(command.element), ENCODER); 
     155            String ret = set(command.element); 
     156            if (!command.noreply) 
     157                r.out.putString(ret, ENCODER); 
     158        } else if (cmd == Commands.CAS) { 
     159            String ret = cas(command.cas_key, command.element); 
     160            if (!command.noreply) 
     161                r.out.putString(ret, ENCODER); 
    156162        } else if (cmd == Commands.ADD) { 
    157             r.out.putString(add(command.element), ENCODER); 
     163            String ret = add(command.element); 
     164            if (!command.noreply) 
     165                r.out.putString(ret, ENCODER); 
    158166        } else if (cmd == Commands.REPLACE) { 
    159             r.out.putString(replace(command.element), ENCODER); 
     167            String ret = replace(command.element); 
     168            if (!command.noreply) 
     169                r.out.putString(ret, ENCODER); 
    160170        } else if (cmd == Commands.INCR) { 
    161171            r.out.putString(get_add(command.keys.get(0), parseInt(command.keys.get(1))), ENCODER); 
     
    207217    /** 
    208218     * Triggered when a session has gone idle. 
     219     * 
    209220     * @param session the MINA session 
    210      * @param status the idle status 
     221     * @param status  the idle status 
    211222     */ 
    212223    public void sessionIdle(IoSession session, IdleStatus status) { 
     
    217228    /** 
    218229     * Triggered when an exception is caught by the protocol handler 
     230     * 
    219231     * @param session the MINA session 
    220      * @param cause the exception 
     232     * @param cause   the exception 
    221233     */ 
    222234    public void exceptionCaught(IoSession session, Throwable cause) { 
     
    230242     * Handle the deletion of an item from the cache. 
    231243     * 
    232      * @param key the key for the item 
     244     * @param key  the key for the item 
    233245     * @param time only delete the element if time (time in seconds) 
    234246     * @return the message response 
     
    246258     */ 
    247259    protected String add(MCElement e) { 
    248         if (cache.add(e)) return "STORED\r\n"; 
     260        if (cache.add(e) == Cache.StoreResponse.STORED) return "STORED\r\n"; 
    249261        else return "NOT_STORED\r\n"; 
     262    } 
     263 
     264    protected String getStoreResponeString(Cache.StoreResponse storeResponse) { 
     265        switch (storeResponse) { 
     266            case EXISTS: 
     267                return "EXISTS\r\n"; 
     268            case NOT_FOUND: 
     269                return "NOT_FOUND\r\n"; 
     270            case NOT_STORED: 
     271                return "NOT_STORED\r\n"; 
     272            case STORED: 
     273                return "STORED\r\n"; 
     274        } 
     275        return null; 
    250276    } 
    251277 
     
    257283     */ 
    258284    protected String replace(MCElement e) { 
    259         if (cache.replace(e)) return "STORED\r\n"; 
    260         else return "NOT_STORED\r\n"; 
     285        return getStoreResponeString(cache.replace(e)); 
    261286    } 
    262287 
     
    268293     */ 
    269294    protected String set(MCElement e) { 
    270         if (cache.set(e)) return "STORED\r\n"; 
    271         else return "NOT_STORED\r\n"; 
    272     } 
    273  
    274     /** 
    275      * Increment an (integer) element inthe cache 
     295        return getStoreResponeString(cache.set(e)); 
     296    } 
     297 
     298    /** 
     299     * Check and set an element in the cache 
     300     * 
     301     * @param cas_key 
     302     * @param e       the element to set @return the message response string 
     303     */ 
     304    protected String cas(Long cas_key, MCElement e) { 
     305        return getStoreResponeString(cache.cas(cas_key, e)); 
     306    } 
     307 
     308    /** 
     309     * Increment an (integer) element in the cache 
     310     * 
    276311     * @param key the key to increment 
    277312     * @param mod the amount to add to the value 
     
    289324    /** 
    290325     * Check whether an element is in the cache and non-expired 
     326     * 
    291327     * @param key the key for the element to lookup 
    292328     * @return whether the element is in the cache and is live 
     
    298334    /** 
    299335     * Get an element from the cache 
     336     * 
    300337     * @param key the key for the element to lookup 
    301338     * @return the element, or 'null' in case of cache miss. 
     
    326363    /** 
    327364     * Return runtime statistics 
     365     * 
    328366     * @param arg additional arguments to the stats command 
    329367     * @return the full command response 
     
    372410    /** 
    373411     * Flush all cache entries 
     412     * 
    374413     * @return command response 
    375414     */ 
     
    380419    /** 
    381420     * Flush all cache entries with a timestamp after a given expiration time 
     421     * 
    382422     * @param expire the flush time in seconds 
    383423     * @return command response 
     
    388428 
    389429 
    390  
    391  
    392  
    393430}