jruby-memcached-thoughtworks 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,165 @@
1
+ package net.spy.memcached;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.Collection;
5
+ import java.util.Iterator;
6
+ import java.util.List;
7
+ import java.util.Map;
8
+ import java.util.SortedMap;
9
+ import java.util.TreeMap;
10
+
11
+ import net.spy.memcached.compat.SpyObject;
12
+ import net.spy.memcached.util.DefaultKetamaNodeLocatorConfiguration;
13
+ import net.spy.memcached.util.KetamaNodeLocatorConfiguration;
14
+
15
+ /**
16
+ * This is grabbed from spymemcached.
17
+ *
18
+ * hashAlg should only be used to get server by key.
19
+ *
20
+ */
21
+ public final class KetamaNodeLocator extends SpyObject implements NodeLocator {
22
+
23
+ private volatile TreeMap<Long, MemcachedNode> ketamaNodes;
24
+ private final Collection<MemcachedNode> allNodes;
25
+
26
+ private final HashAlgorithm hashAlg;
27
+ private final KetamaNodeLocatorConfiguration config;
28
+
29
+ /**
30
+ * Create a new KetamaNodeLocator using specified nodes and the specifed hash
31
+ * algorithm.
32
+ *
33
+ * @param nodes The List of nodes to use in the Ketama consistent hash
34
+ * continuum
35
+ * @param alg The hash algorithm to use when choosing a node in the Ketama
36
+ * consistent hash continuum
37
+ */
38
+ public KetamaNodeLocator(List<MemcachedNode> nodes, HashAlgorithm alg) {
39
+ this(nodes, alg, new DefaultKetamaNodeLocatorConfiguration());
40
+ }
41
+
42
+ /**
43
+ * Create a new KetamaNodeLocator using specified nodes and the specifed hash
44
+ * algorithm and configuration.
45
+ *
46
+ * @param nodes The List of nodes to use in the Ketama consistent hash
47
+ * continuum
48
+ * @param alg The hash algorithm to use when choosing a node in the Ketama
49
+ * consistent hash continuum
50
+ * @param conf
51
+ */
52
+ public KetamaNodeLocator(List<MemcachedNode> nodes, HashAlgorithm alg,
53
+ KetamaNodeLocatorConfiguration conf) {
54
+ super();
55
+ allNodes = nodes;
56
+ hashAlg = alg;
57
+ config = conf;
58
+ setKetamaNodes(nodes);
59
+ }
60
+
61
+ private KetamaNodeLocator(TreeMap<Long, MemcachedNode> smn,
62
+ Collection<MemcachedNode> an, HashAlgorithm alg,
63
+ KetamaNodeLocatorConfiguration conf) {
64
+ super();
65
+ ketamaNodes = smn;
66
+ allNodes = an;
67
+ hashAlg = alg;
68
+ config = conf;
69
+ }
70
+
71
+ public Collection<MemcachedNode> getAll() {
72
+ return allNodes;
73
+ }
74
+
75
+ public MemcachedNode getPrimary(final String k) {
76
+ MemcachedNode rv = getNodeForKey(hashAlg.hash(k));
77
+ assert rv != null : "Found no node for key " + k;
78
+ return rv;
79
+ }
80
+
81
+ long getMaxKey() {
82
+ return getKetamaNodes().lastKey();
83
+ }
84
+
85
+ MemcachedNode getNodeForKey(long hash) {
86
+ final MemcachedNode rv;
87
+ if (!ketamaNodes.containsKey(hash)) {
88
+ // Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5
89
+ // in a lot of places, so I'm doing this myself.
90
+ SortedMap<Long, MemcachedNode> tailMap = getKetamaNodes().tailMap(hash);
91
+ if (tailMap.isEmpty()) {
92
+ hash = getKetamaNodes().firstKey();
93
+ } else {
94
+ hash = tailMap.firstKey();
95
+ }
96
+ }
97
+ rv = getKetamaNodes().get(hash);
98
+ return rv;
99
+ }
100
+
101
+ public Iterator<MemcachedNode> getSequence(String k) {
102
+ // Seven searches gives us a 1 in 2^7 chance of hitting the
103
+ // same dead node all of the time.
104
+ return new KetamaIterator(k, 7, getKetamaNodes(), hashAlg);
105
+ }
106
+
107
+ public NodeLocator getReadonlyCopy() {
108
+ TreeMap<Long, MemcachedNode> smn =
109
+ new TreeMap<Long, MemcachedNode>(getKetamaNodes());
110
+ Collection<MemcachedNode> an =
111
+ new ArrayList<MemcachedNode>(allNodes.size());
112
+
113
+ // Rewrite the values a copy of the map.
114
+ for (Map.Entry<Long, MemcachedNode> me : smn.entrySet()) {
115
+ me.setValue(new MemcachedNodeROImpl(me.getValue()));
116
+ }
117
+
118
+ // Copy the allNodes collection.
119
+ for (MemcachedNode n : allNodes) {
120
+ an.add(new MemcachedNodeROImpl(n));
121
+ }
122
+
123
+ return new KetamaNodeLocator(smn, an, hashAlg, config);
124
+ }
125
+
126
+ @Override
127
+ public void updateLocator(List<MemcachedNode> nodes) {
128
+ setKetamaNodes(nodes);
129
+ }
130
+
131
+ /**
132
+ * @return the ketamaNodes
133
+ */
134
+ protected TreeMap<Long, MemcachedNode> getKetamaNodes() {
135
+ return ketamaNodes;
136
+ }
137
+
138
+ /**
139
+ * Setup the KetamaNodeLocator with the list of nodes it should use.
140
+ *
141
+ * @param nodes a List of MemcachedNodes for this KetamaNodeLocator to use in
142
+ * its continuum
143
+ */
144
+ protected void setKetamaNodes(List<MemcachedNode> nodes) {
145
+ TreeMap<Long, MemcachedNode> newNodeMap =
146
+ new TreeMap<Long, MemcachedNode>();
147
+ int numReps = config.getNodeRepetitions();
148
+ for (MemcachedNode node : nodes) {
149
+ for (int i = 0; i < numReps / 4; i++) {
150
+ byte[] digest =
151
+ DefaultHashAlgorithm.computeMd5(config.getKeyForNode(node, i));
152
+ for (int h = 0; h < 4; h++) {
153
+ Long k = ((long) (digest[3 + h * 4] & 0xFF) << 24)
154
+ | ((long) (digest[2 + h * 4] & 0xFF) << 16)
155
+ | ((long) (digest[1 + h * 4] & 0xFF) << 8)
156
+ | (digest[h * 4] & 0xFF);
157
+ newNodeMap.put(k, node);
158
+ getLogger().debug("Adding node %s in position %d", node, k);
159
+ }
160
+ }
161
+ }
162
+ assert newNodeMap.size() == numReps * nodes.size();
163
+ ketamaNodes = newNodeMap;
164
+ }
165
+ }
@@ -0,0 +1,104 @@
1
+ package net.spy.memcached.util;
2
+
3
+ import java.net.InetSocketAddress;
4
+ import java.util.HashMap;
5
+ import java.util.Map;
6
+
7
+ import net.spy.memcached.MemcachedNode;
8
+
9
+ /**
10
+ * This is grabbed from spymemcached.
11
+ *
12
+ * socket address in libmemcached 0.32 is
13
+ * 127.0.0.1-1 (port is 11211) or
14
+ * 127.0.0.1:43043-1 (port is not 11211)
15
+ */
16
+ public class DefaultKetamaNodeLocatorConfiguration implements
17
+ KetamaNodeLocatorConfiguration {
18
+
19
+ private final int numReps = 160;
20
+ static final int DEFAULT_PORT = 11211;
21
+
22
+ // Internal lookup map to try to carry forward the optimisation that was
23
+ // previously in KetamaNodeLocator
24
+ protected Map<MemcachedNode, String> socketAddresses =
25
+ new HashMap<MemcachedNode, String>();
26
+
27
+ /**
28
+ * Returns the socket address of a given MemcachedNode.
29
+ *
30
+ * @param node The node which we're interested in
31
+ * @return String the socket address of that node.
32
+ */
33
+ protected String getSocketAddressForNode(MemcachedNode node) {
34
+ // Using the internal map retrieve the socket addresses
35
+ // for given nodes.
36
+ // I'm aware that this code is inherently thread-unsafe as
37
+ // I'm using a HashMap implementation of the map, but the worst
38
+ // case ( I believe) is we're slightly in-efficient when
39
+ // a node has never been seen before concurrently on two different
40
+ // threads, so it the socketaddress will be requested multiple times!
41
+ // all other cases should be as fast as possible.
42
+ String result = socketAddresses.get(node);
43
+ if (result == null) {
44
+ InetSocketAddress socketAddress = (InetSocketAddress) node.getSocketAddress();
45
+ if (socketAddress.getPort() == DEFAULT_PORT) {
46
+ result = socketAddress.getAddress().getHostAddress();
47
+ } else {
48
+ result = socketAddress.getAddress().getHostAddress() + ":" + socketAddress.getPort();
49
+ }
50
+ socketAddresses.put(node, result);
51
+ }
52
+ return result;
53
+ }
54
+
55
+ /**
56
+ * Returns the number of discrete hashes that should be defined for each node
57
+ * in the continuum.
58
+ *
59
+ * @return NUM_REPS repetitions.
60
+ */
61
+ public int getNodeRepetitions() {
62
+ return numReps;
63
+ }
64
+
65
+ /**
66
+ * Returns a uniquely identifying key, suitable for hashing by the
67
+ * KetamaNodeLocator algorithm.
68
+ *
69
+ * <p>
70
+ * This default implementation uses the socket-address of the MemcachedNode
71
+ * and concatenates it with a hyphen directly against the repetition number
72
+ * for example a key for a particular server's first repetition may look like:
73
+ * <p>
74
+ *
75
+ * <p>
76
+ * <code>myhost/10.0.2.1-0</code>
77
+ * </p>
78
+ *
79
+ * <p>
80
+ * for the second repetition
81
+ * </p>
82
+ *
83
+ * <p>
84
+ * <code>myhost/10.0.2.1-1</code>
85
+ * </p>
86
+ *
87
+ * <p>
88
+ * for a server where reverse lookups are failing the returned keys may look
89
+ * like
90
+ * </p>
91
+ *
92
+ * <p>
93
+ * <code>/10.0.2.1-0</code> and <code>/10.0.2.1-1</code>
94
+ * </p>
95
+ *
96
+ * @param node The MemcachedNode to use to form the unique identifier
97
+ * @param repetition The repetition number for the particular node in question
98
+ * (0 is the first repetition)
99
+ * @return The key that represents the specific repetition of the node
100
+ */
101
+ public String getKeyForNode(MemcachedNode node, int repetition) {
102
+ return getSocketAddressForNode(node) + "-" + repetition;
103
+ }
104
+ }
Binary file
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jruby-memcached-thoughtworks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Bill DePhillips
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mocha
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: jruby memcacached client which is compatible with memcached gem
42
+ email:
43
+ - bill.dephillips@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .travis.yml
50
+ - CHANGELOG.md
51
+ - Gemfile
52
+ - MIT-LICENSE
53
+ - README.md
54
+ - Rakefile
55
+ - benchmark.rb
56
+ - jruby_memcached.gemspec
57
+ - lib/memcached.rb
58
+ - lib/memcached/version.rb
59
+ - pom.xml
60
+ - spec/memcached_spec.rb
61
+ - spec/rails_spec.rb
62
+ - spec/spec_helper.rb
63
+ - spec/timeout_spec.rb
64
+ - src/main/java/com/openfeint/memcached/Memcached.java
65
+ - src/main/java/com/openfeint/memcached/MemcachedService.java
66
+ - src/main/java/com/openfeint/memcached/Rails.java
67
+ - src/main/java/com/openfeint/memcached/error/ATimeoutOccurred.java
68
+ - src/main/java/com/openfeint/memcached/error/Error.java
69
+ - src/main/java/com/openfeint/memcached/error/NotFound.java
70
+ - src/main/java/com/openfeint/memcached/error/NotStored.java
71
+ - src/main/java/com/openfeint/memcached/error/NotSupport.java
72
+ - src/main/java/com/openfeint/memcached/transcoder/MarshalTranscoder.java
73
+ - src/main/java/com/openfeint/memcached/transcoder/MarshalZlibTranscoder.java
74
+ - src/main/java/net/spy/memcached/KetamaNodeLocator.java
75
+ - src/main/java/net/spy/memcached/util/DefaultKetamaNodeLocatorConfiguration.java
76
+ - target/spymemcached-ext-0.0.2.jar
77
+ homepage: https://github.com/ThoughtWorksStudios/jruby-memcached
78
+ licenses: []
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.3.0
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: jruby compatible memcached client
100
+ test_files:
101
+ - spec/memcached_spec.rb
102
+ - spec/rails_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/timeout_spec.rb