ruby_skynet 0.8.1 → 1.0.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,75 @@
1
+ require 'thread_safe'
2
+ require 'semantic_logger'
3
+ require 'ruby_skynet/zookeeper/registry'
4
+
5
+ #
6
+ # CachedRegistry
7
+ #
8
+ # Store information in ZooKeeper and subscribe to future changes
9
+ # and keep a local copy of the information in ZooKeeper
10
+ #
11
+ # Notifies registered subscribers when information has changed
12
+ #
13
+ # All paths specified are relative to the root_path. As such the root key
14
+ # is never returned, nor is it required when a key is supplied as input.
15
+ # For example, with a root_path of /foo/bar, any paths passed in will leave
16
+ # out the root_path: host/name
17
+ #
18
+ # Keeps a local copy in memory of all descendant values of the supplied root_path
19
+ # Supports high-frequency calls to retrieve registry data
20
+ # The in-memory cache will be kept in synch with any changes on the server
21
+ module RubySkynet
22
+ module Zookeeper
23
+ class CachedRegistry < Registry
24
+ # Logging instance for this class
25
+ include SemanticLogger::Loggable
26
+
27
+ # Create a CachedRegistry instance to manage information within the Registry
28
+ # and keep a local cached copy of the data in the Registry to support
29
+ # high-speed or frequent reads.
30
+ #
31
+ # Writes are sent to ZooKeeper and then replicated back to the local cache
32
+ # only once ZooKeeper has updated its store
33
+ #
34
+ # See RubySkynet::Zookeeper::Registry for the complete list of options
35
+ #
36
+ def initialize(params)
37
+ @cache = ThreadSafe::Hash.new
38
+ # Supplied block to load the current keys from the Registry
39
+ super(params) do |key, value, version|
40
+ @cache[key] = value
41
+ end
42
+
43
+ on_create {|key, value| @cache[key] = value}
44
+ on_update {|key, value, version| @cache[key] = value}
45
+ on_delete {|key| @cache.delete(key)}
46
+ end
47
+
48
+ # Retrieve the latest value from a specific key from the registry
49
+ def [](key)
50
+ @cache[key]
51
+ end
52
+
53
+ # Iterate over every key, value pair in the registry at the root_path
54
+ #
55
+ # Example:
56
+ # registry.each_pair {|k,v| puts "#{k} => #{v}"}
57
+ def each_pair(&block)
58
+ # Have to duplicate the cache otherwise concurrent changes to the
59
+ # registry will interfere with the iterator
60
+ @cache.dup.each_pair(&block)
61
+ end
62
+
63
+ # Returns [Array<String>] all keys in the registry
64
+ def keys
65
+ @cache.keys
66
+ end
67
+
68
+ # Returns a copy of the registry as a Hash
69
+ def to_h
70
+ @cache.dup
71
+ end
72
+
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,27 @@
1
+ # This monkey-patch must be removed when ticket #44 has been included in
2
+ # an updated ZooKeeper Gem
3
+ # Ticket: https://github.com/slyphon/zookeeper/issues/44
4
+ # Pull Request: https://github.com/slyphon/zookeeper/pull/45
5
+
6
+ module Zookeeper
7
+ class JavaBase
8
+
9
+ def get(req_id, path, callback, watcher)
10
+ handle_keeper_exception do
11
+ watch_cb = watcher ? create_watcher(req_id, path) : false
12
+
13
+ if callback
14
+ jzk.getData(path, watch_cb, JavaCB::DataCallback.new(req_id), event_queue)
15
+ [Code::Ok, nil, nil] # the 'nil, nil' isn't strictly necessary here
16
+ else # sync
17
+ stat = JZKD::Stat.new
18
+ value = jzk.getData(path, watch_cb, stat)
19
+ data = String.from_java_bytes(value) unless value.nil?
20
+
21
+ [Code::Ok, data, stat.to_hash]
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,64 @@
1
+ require 'yaml'
2
+ require 'multi_json'
3
+ module RubySkynet
4
+ module Zookeeper
5
+ module Json
6
+
7
+ # Deserialize from JSON entries in Zookeeper
8
+ module Deserializer
9
+ def self.deserialize(value)
10
+ return value if value.nil? || (value == '')
11
+
12
+ if value.strip.start_with?('{') || value.strip.start_with?('[{')
13
+ symbolize(MultiJson.load(value))
14
+ else
15
+ symbolize_string(value)
16
+ end
17
+ end
18
+
19
+ # Returns the supplied value symbolized
20
+ def self.symbolize(v)
21
+ if v.is_a?(Hash)
22
+ symbolize_hash(v)
23
+ elsif v.is_a?(Array)
24
+ symbolize_array(v)
25
+ elsif v.is_a?(String)
26
+ symbolize_string(v)
27
+ else
28
+ v
29
+ end
30
+ end
31
+
32
+ # Returns a new hash updated with keys and values that are strings
33
+ # starting with ':' are turned into symbols
34
+ def self.symbolize_hash(hash)
35
+ h = hash.dup
36
+ hash.each_pair do |k, v|
37
+ # Convert values in the hash
38
+ h[k] = symbolize(v)
39
+
40
+ # Convert key to a symbol if it is a symbol string
41
+ h[k[1..-1].to_sym] = h.delete(k) if k.is_a?(String) && k.start_with?(':')
42
+ end
43
+ h
44
+ end
45
+
46
+ # Returns a new Array with any symbols strings returned as symbols
47
+ def self.symbolize_array(a)
48
+ a.collect {|v| symbolize(v)}
49
+ end
50
+
51
+ # Returns a new string with the string parsed and symbol string converted to a symbol
52
+ def self.symbolize_string(s)
53
+ # JSON Parser cannot parse non-hash/array values
54
+ value = YAML.load(s)
55
+ # Now check for symbols which are strings starting with ':'
56
+ value.is_a?(String) && value.start_with?(':') ? value[1..-1].to_sym : value
57
+ rescue Exception
58
+ s
59
+ end
60
+
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,57 @@
1
+ require 'multi_json'
2
+ module RubySkynet
3
+ module Zookeeper
4
+ module Json
5
+
6
+ # Serialize to JSON for storing in Doozer
7
+ module Serializer
8
+ def self.serialize(value)
9
+ if value.is_a?(Hash) || value.is_a?(Array)
10
+ MultiJson.encode(desymbolize(value))
11
+ elsif value.is_a?(Symbol)
12
+ desymbolize_symbol(value)
13
+ else
14
+ value.to_s
15
+ end
16
+ end
17
+
18
+ # Returns the supplied value with symbols converted to a string prefixed
19
+ # with ':'
20
+ def self.desymbolize(v)
21
+ if v.is_a?(Hash)
22
+ desymbolize_hash(v)
23
+ elsif v.is_a?(Array)
24
+ desymbolize_array(v)
25
+ elsif v.is_a?(Symbol)
26
+ desymbolize_symbol(v)
27
+ else
28
+ v.to_s
29
+ end
30
+ end
31
+
32
+ # Returns a new hash with all symbol keys and values as strings starting with ':'
33
+ def self.desymbolize_hash(hash)
34
+ h = hash.dup
35
+ hash.each_pair do |k, v|
36
+ # Convert values in the hash
37
+ h[k] = desymbolize(v)
38
+
39
+ # Convert key to a string if it is a symbol
40
+ h[desymbolize_symbol(k)] = h.delete(k) if k.is_a?(Symbol)
41
+ end
42
+ h
43
+ end
44
+
45
+ # Returns a new Array with any symbols returned as symbol strings
46
+ def self.desymbolize_array(a)
47
+ a.collect {|v| desymbolize(v)}
48
+ end
49
+
50
+ def self.desymbolize_symbol(s)
51
+ ":#{s}"
52
+ end
53
+
54
+ end
55
+ end
56
+ end
57
+ end