EMMA Coverage Report (generated Tue Oct 27 11:32:50 PDT 2009)
[all classes][net.spy.memcached]

COVERAGE SUMMARY FOR SOURCE FILE [CASMutator.java]

nameclass, %method, %block, %line, %
CASMutator.java100% (1/1)100% (4/4)94%  (120/127)97%  (29.2/30)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class CASMutator100% (1/1)100% (4/4)94%  (120/127)97%  (29.2/30)
<static initializer> 100% (1/1)75%  (6/8)75%  (0.8/1)
cas (String, Object, int, CASMutation): Object 100% (1/1)95%  (96/101)97%  (21.4/22)
CASMutator (MemcachedClientIF, Transcoder): void 100% (1/1)100% (6/6)100% (2/2)
CASMutator (MemcachedClientIF, Transcoder, int): void 100% (1/1)100% (12/12)100% (5/5)

1package net.spy.memcached;
2 
3import net.spy.memcached.compat.SpyObject;
4import net.spy.memcached.transcoders.Transcoder;
5 
6/**
7 * Object that provides mutation via CAS over a given memcache client.
8 *
9 * <p>Example usage (reinventing incr):</p>
10 *
11 * <pre>
12 * // Get or create a client.
13 * MemcachedClient client=[...];
14 *
15 * // Get a Transcoder.
16 * Transcoder<Long> tc = new LongTranscoder();
17 *
18 * // Get a mutator instance that uses that client.
19 * CASMutator&lt;Long&gt; mutator=new CASMutator&lt;Long&gt;(client, tc);
20 *
21 * // Get a mutation that knows what to do when a value is found.
22 * CASMutation&lt;Long&gt; mutation=new CASMutation&lt;Long&gt;() {
23 *     public Long getNewValue(Long current) {
24 *         return current + 1;
25 *     }
26 * };
27 *
28 * // Do a mutation.
29 * long currentValue=mutator.cas(someKey, 0L, 0, mutation);
30 * </pre>
31 */
32public class CASMutator<T> extends SpyObject {
33 
34        private static final int MAX_TRIES=8192;
35 
36        private final MemcachedClientIF client;
37        private final Transcoder<T> transcoder;
38        private final int max;
39 
40        /**
41         * Construct a CASMutator that uses the given client.
42         *
43         * @param c the client
44         * @param tc the Transcoder to use
45         * @param max_tries the maximum number of attempts to get a CAS to succeed
46         */
47        public CASMutator(MemcachedClientIF c, Transcoder<T> tc, int max_tries) {
48                super();
49                client=c;
50                transcoder=tc;
51                max=max_tries;
52        }
53 
54        /**
55         * Construct a CASMutator that uses the given client.
56         *
57         * @param c the client
58         * @param tc the Transcoder to use
59         */
60        public CASMutator(MemcachedClientIF c, Transcoder<T> tc) {
61                this(c, tc, MAX_TRIES);
62        }
63 
64        /**
65         * CAS a new value in for a key.
66         *
67         * <p>
68         * Note that if initial is null, this method will only update existing
69         * values.
70         * </p>
71         *
72         * @param key the key to be CASed
73         * @param initial the value to use when the object is not cached
74         * @param initialExp the expiration time to use when initializing
75         * @param m the mutation to perform on an object if a value exists for the
76         *          key
77         * @return the new value that was set
78         */
79        public T cas(final String key, final T initial, int initialExp,
80                        final CASMutation<T> m) throws Exception {
81                T rv=initial;
82 
83                boolean done=false;
84                for(int i=0; !done && i<max; i++) {
85                        CASValue<T> casval=client.gets(key, transcoder);
86                        T current=null;
87                        // If there were a CAS value, check to see if it's compatible.
88                        if(casval != null) {
89                                T tmp = casval.getValue();
90                                current=tmp;
91                        }
92                        // If we have anything mutate and CAS, else add.
93                        if(current != null) {
94                                // Declaring this impossible since the only way current can
95                                // be non-null is if casval was set.
96                                assert casval != null : "casval was null with a current value";
97 
98                                rv=m.getNewValue(current);
99                                // There are three possibilities here:
100                                //  1) It worked and we're done.
101                                //  2) It collided and we need to reload and try again.
102                                //  3) It disappeared between our fetch and our cas.
103                                // We're ignoring #3 because it's *extremely* unlikely and the
104                                // behavior will be fine in this code -- we'll do another gets
105                                // and follow it up with either an add or another cas depending
106                                // on whether it exists the next time.
107                                if(client.cas(key, casval.getCas(), rv, transcoder)
108                                                == CASResponse.OK) {
109                                        done=true;
110                                }
111                        } else {
112                                // No value found, try an add.
113                                if(initial == null) {
114                                        done = true;
115                                        rv = null;
116                                } else if(client.add(key, initialExp, initial, transcoder).get()) {
117                                        done=true;
118                                        rv=initial;
119                                }
120                        }
121                }
122                if(!done) {
123                        throw new RuntimeException("Couldn't get a CAS in " + max
124                                + " attempts");
125                }
126 
127                return rv;
128        }
129}

[all classes][net.spy.memcached]
EMMA 2.0.5312 (C) Vladimir Roubtsov