boogaloo 0.1

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.
Files changed (57) hide show
  1. data/CHANGELOG +2 -0
  2. data/DEBUGGING +4 -0
  3. data/MIT-LICENSE +7 -0
  4. data/README +106 -0
  5. data/RUNNING_UNIT_TESTS +5 -0
  6. data/Rakefile +44 -0
  7. data/bin/boogaloo +159 -0
  8. data/doc/classes/Boogaloo.html +149 -0
  9. data/doc/classes/Boogaloo/Cache.html +121 -0
  10. data/doc/classes/Boogaloo/Cache/Base.html +664 -0
  11. data/doc/classes/Boogaloo/Cache/Persistent.html +122 -0
  12. data/doc/classes/Boogaloo/Cache/Temporary.html +439 -0
  13. data/doc/classes/Boogaloo/Client.html +111 -0
  14. data/doc/classes/Boogaloo/Client/Connection.html +228 -0
  15. data/doc/classes/Boogaloo/Config.html +540 -0
  16. data/doc/classes/Boogaloo/ServiceGateway.html +176 -0
  17. data/doc/classes/Boogaloo/ServiceRequest.html +210 -0
  18. data/doc/classes/Boogaloo/ThreadPool.html +205 -0
  19. data/doc/classes/Boogaloo/WorkerThread.html +239 -0
  20. data/doc/created.rid +1 -0
  21. data/doc/files/DEBUGGING.html +113 -0
  22. data/doc/files/MIT-LICENSE.html +129 -0
  23. data/doc/files/README.html +261 -0
  24. data/doc/files/examples/boogaloo_conf.html +130 -0
  25. data/doc/files/lib/boogaloo/cache/base_rb.html +101 -0
  26. data/doc/files/lib/boogaloo/cache/persistent_rb.html +108 -0
  27. data/doc/files/lib/boogaloo/cache/temporary_rb.html +101 -0
  28. data/doc/files/lib/boogaloo/client/connection_rb.html +101 -0
  29. data/doc/files/lib/boogaloo/config_rb.html +109 -0
  30. data/doc/files/lib/boogaloo/service_gateway_rb.html +110 -0
  31. data/doc/files/lib/boogaloo/service_request_rb.html +108 -0
  32. data/doc/files/lib/boogaloo/thread_pool_rb.html +101 -0
  33. data/doc/files/lib/boogaloo/util_rb.html +240 -0
  34. data/doc/files/lib/boogaloo/version_rb.html +114 -0
  35. data/doc/files/lib/boogaloo/worker_thread_rb.html +101 -0
  36. data/doc/fr_class_index.html +38 -0
  37. data/doc/fr_file_index.html +41 -0
  38. data/doc/fr_method_index.html +67 -0
  39. data/doc/index.html +24 -0
  40. data/doc/rdoc-style.css +208 -0
  41. data/examples/boogaloo.conf +17 -0
  42. data/lib/boogaloo/cache/base.rb +222 -0
  43. data/lib/boogaloo/cache/persistent.rb +15 -0
  44. data/lib/boogaloo/cache/temporary.rb +173 -0
  45. data/lib/boogaloo/client/connection.rb +55 -0
  46. data/lib/boogaloo/config.rb +206 -0
  47. data/lib/boogaloo/service_gateway.rb +37 -0
  48. data/lib/boogaloo/service_request.rb +39 -0
  49. data/lib/boogaloo/thread_pool.rb +40 -0
  50. data/lib/boogaloo/util.rb +29 -0
  51. data/lib/boogaloo/version.rb +1 -0
  52. data/lib/boogaloo/worker_thread.rb +46 -0
  53. data/test/test_persistent_cache.rb +99 -0
  54. data/test/test_service_gateway.rb +27 -0
  55. data/test/test_synchronicity.rb +29 -0
  56. data/test/test_temporary_cache.rb +42 -0
  57. metadata +113 -0
@@ -0,0 +1,17 @@
1
+ # Example Boogaloo configuration.
2
+
3
+ Server:
4
+ host: localhost
5
+ port: 7777
6
+ worker_threads: 3
7
+
8
+ PersistentCaches:
9
+
10
+ MainCache:
11
+ instance_name: main_cache
12
+
13
+ TemporaryCaches:
14
+
15
+ TempCache:
16
+ instance_name: temp_cache
17
+ check_frequency: 10
@@ -0,0 +1,222 @@
1
+ module Boogaloo
2
+
3
+ module Cache
4
+
5
+ # Provides fundemental cache operations such as add, set, get and various statistical operations.
6
+ class Base
7
+
8
+ include DRbUndumped
9
+
10
+ # Initialize a new base cache instance.
11
+ #
12
+ # Parameters:
13
+ # name: The name of the cache
14
+ # config: A Hash containing configuration for the cache.
15
+ def initialize(name, config)
16
+
17
+ @name = name
18
+ @config = config
19
+ reset
20
+
21
+ end
22
+
23
+ # Get an object from the cache.
24
+ #
25
+ # Parameters:
26
+ # +namespace+:: The namespace to get the object from. Use <tt>nil</tt> if global namespace should be used.
27
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
28
+ def get(namespace, key)
29
+
30
+ debug("[#{@name}] GET: #{namespace or 'nil'}, #{key}") if $debug
31
+
32
+ if namespace.nil?
33
+
34
+ @global_store.key?(key) ? @hit += 1 : @miss += 1
35
+ @global_store[key]
36
+
37
+ else
38
+
39
+ @miss += 1 and return nil if not @namespace_store.key?(namespace)
40
+ @namespace_store[namespace].key?(key) ? @hit += 1 : @miss += 1
41
+ @namespace_store[namespace][key]
42
+
43
+ end
44
+
45
+ end
46
+
47
+ # Pull and object from the cache (get and delete).
48
+ #
49
+ # Parameters:
50
+ # +namespace+:: The namespace to get the object from. Use <tt>nil</tt> if global namespace should be used.
51
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
52
+ def pull(namespace, key)
53
+
54
+ debug("[#{@name}] PULL: #{namespace or 'nil'}, #{key}") if $debug
55
+
56
+ if namespace.nil?
57
+
58
+ @global_store.key?(key) ? @hit += 1 : @miss += 1
59
+ @global_store.delete(key)
60
+
61
+ else
62
+
63
+ @miss += 1 and return nil if not @namespace_store.key?(namespace)
64
+ @namespace_store[namespace].key?(key) ? @hit += 1 : @miss += 1
65
+ ret = @namespace_store[namespace].delete(key)
66
+ @namespace_store.delete(namespace) if @namespace_store[namespace].size == 0
67
+ ret
68
+
69
+ end
70
+
71
+ end
72
+
73
+ # Add an object to the cache only if it doesn't already exist.
74
+ #
75
+ # Parameters:
76
+ # +namespace+:: The namespace in which the object will exist. Use <tt>nil</tt> if global namespace should be used.
77
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
78
+ # +obj+:: The object to add to the cache.
79
+ def add(namespace, key, obj)
80
+
81
+ return nil_error if obj.nil?
82
+ debug("[#{@name}] ADD: #{namespace or 'nil'}, #{key}") if $debug
83
+
84
+ if namespace.nil?
85
+
86
+ @global_store[key] = obj if not @global_store.key?(key)
87
+
88
+ else
89
+
90
+ create_namespace(namespace)
91
+ @namespace_store[namespace][key] = obj if not @namespace_store[namespace].key?(key)
92
+
93
+ end
94
+
95
+ end
96
+
97
+ # Add an object to the cache, overwriting if one already exists.
98
+ #
99
+ # Parameters:
100
+ # +namespace+:: The namespace in which the object will exist. Use <tt>nil</tt> if global namespace should be used.
101
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
102
+ # +obj+:: The object to add to the cache.
103
+ def set(namespace, key, obj)
104
+
105
+ return nil_error if obj.nil?
106
+ debug("[#{@name}] SET: #{namespace or 'nil'}, #{key}") if $debug
107
+
108
+ if namespace.nil?
109
+
110
+ @global_store[key] = obj
111
+
112
+ else
113
+
114
+ create_namespace(namespace)
115
+ @namespace_store[namespace][key] = obj
116
+
117
+ end
118
+
119
+ end
120
+
121
+ # Returns all available statistics in an Array.
122
+ #
123
+ # Array elements:
124
+ #
125
+ # <tt>0</tt>:: stat_reset_at
126
+ # <tt>1</tt>:: stat_hits
127
+ # <tt>2</tt>:: stat_misses
128
+ # <tt>3</tt>:: stat_namespaces
129
+ # <tt>4</tt>:: stat_objects
130
+ def stat_all
131
+
132
+ return [stat_reset_at, stat_hits, stat_misses, stat_namespaces, stat_objects]
133
+
134
+ end
135
+
136
+ # The time the cache was created or last reset.
137
+ def stat_reset_at
138
+
139
+ @reset_at
140
+
141
+ end
142
+
143
+ # The number of successful cache gets.
144
+ def stat_hits
145
+
146
+ @hit
147
+
148
+ end
149
+
150
+ # The number of unsuccessful cache gets.
151
+ def stat_misses
152
+
153
+ @miss
154
+
155
+ end
156
+
157
+ # The number of namespaces (plus the global namespace).
158
+ def stat_namespaces
159
+
160
+ @namespace_store.size + 1
161
+
162
+ end
163
+
164
+ # The number of objects stored in the cache.
165
+ def stat_objects
166
+
167
+ get_obj_count
168
+
169
+ end
170
+
171
+ # Returns an Array of all object keys currently contained in the cache.
172
+ #
173
+ # Array elements:
174
+ #
175
+ # <tt>0</tt>:: Keys in global scope (Array).
176
+ # <tt>1</tt>:: Namespaces and their respective keys (Hash).
177
+ def inspect_keys
178
+
179
+ tmp = {}
180
+ @namespace_store.keys.each { |key| tmp[key] = @namespace_store[key].keys }
181
+ [@global_store.keys, tmp]
182
+
183
+ end
184
+
185
+ # Reset the cache to an empty state.
186
+ def reset
187
+
188
+ @hit = 0
189
+ @miss = 0
190
+ @global_store = {}
191
+ @namespace_store = {}
192
+ @reset_at = Time.now
193
+
194
+ end
195
+
196
+ protected
197
+
198
+ def get_obj_count #:nodoc:
199
+
200
+ i = 0
201
+ @namespace_store.each { |key, value| i += value.size}
202
+ i + @global_store.size
203
+
204
+ end
205
+
206
+ def create_namespace(namespace) #:nodoc:
207
+
208
+ @namespace_store[namespace] = {} if not @namespace_store.key?(namespace)
209
+
210
+ end
211
+
212
+ def nil_error #:nodoc:
213
+
214
+ return TypeError.new("nil objects cannot be stored in the cache.")
215
+
216
+ end
217
+
218
+ end
219
+
220
+ end
221
+
222
+ end
@@ -0,0 +1,15 @@
1
+ require 'boogaloo/cache/base'
2
+
3
+ module Boogaloo
4
+
5
+ module Cache
6
+
7
+ # A persistent cache in which objects persist for the lifetime of the server.
8
+ #
9
+ # See Boogaloo::Cache::Base[link:classes/Boogaloo/Cache/Base.html] for common cache methods.
10
+ class Persistent < Boogaloo::Cache::Base
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,173 @@
1
+ module Boogaloo
2
+
3
+ module Cache
4
+
5
+ # A temporary cache in which objects can expire and are subsequently deleted when they do.
6
+ # The frequency at which the cache is checked for objects to delete is determined by the <tt>check_frequency</tt> parameter.
7
+ #
8
+ # See Boogaloo::Cache::Base[link:classes/Boogaloo/Cache/Base.html] for common cache methods.
9
+ class Temporary < Boogaloo::Cache::Base
10
+
11
+ # Initialize a new temporary cache instance.
12
+ #
13
+ # Parameters:
14
+ # +name+:: The name of the cache
15
+ # +config+:: A Hash containing configuration for the cache.
16
+ # Configuration options:
17
+ # +check_frequency+:: The frequency in seconds at which the cache will check for objects to delete.
18
+ def initialize(name, config)
19
+
20
+ super
21
+
22
+ Thread.new {
23
+
24
+ while true
25
+
26
+ sleep @config['check_frequency'].to_f
27
+
28
+ @global_store.keys.each do |key|
29
+
30
+ times_key = "#{key}_#{@global_store[key].object_id}"
31
+
32
+ if @times[times_key][:time] <= Time.now
33
+
34
+ @global_store.delete(key)
35
+ @times.delete(key)
36
+
37
+ end
38
+
39
+ end
40
+
41
+ @namespace_store.keys.each do |nskey|
42
+
43
+ @namespace_store[nskey].keys.each do |key|
44
+
45
+ times_key = "#{nskey}_#{key}_#{@namespace_store[nskey][key].object_id}"
46
+
47
+ if @times[times_key][:time] <= Time.now
48
+
49
+ @namespace_store[nskey].delete(key)
50
+ @times.delete(times_key)
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ end
59
+
60
+ }
61
+
62
+ end
63
+
64
+ # Add an object to the cache only if it doesn't already exist.
65
+ #
66
+ # Parameters:
67
+ # +namespace+:: The namespace in which the object will exist. Use <tt>nil</tt> if global namespace is desired.
68
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
69
+ # +obj+:: The object to add to the cache.
70
+ # +expires+:: The time in seconds which the object should exist in the cache without being touched before it is deleted.
71
+ def add(namespace, key, obj, expires)
72
+
73
+ check_expires(expires)
74
+ super(namespace, key, obj)
75
+ set_expiration(namespace, key, obj, expires)
76
+
77
+ end
78
+
79
+ # Add an object to the cache, overwriting if one already exists.
80
+ #
81
+ # Parameters:
82
+ # +namespace+:: The namespace in which the object will exist. Use <tt>nil</tt> if global namespace should be used.
83
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
84
+ # +obj+:: The object to add to the cache.
85
+ # +expires+:: The time in seconds which the object should exist in the cache without being touched before it is deleted.
86
+ def set(namespace, key, obj, expires)
87
+
88
+ check_expires(expires)
89
+ super(namespace, key, obj)
90
+ set_expiration(namespace, key, obj, expires)
91
+
92
+ end
93
+
94
+ # Get an object from the cache.
95
+ #
96
+ # Parameters:
97
+ # +namespace+:: The namespace to get the object from. Use <tt>nil</tt> if global namespace should be used.
98
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
99
+ def get(namespace, key)
100
+
101
+ ret = super
102
+ reset_expiration(namespace, key, ret) if not ret.nil?
103
+ ret
104
+
105
+ end
106
+
107
+ # Pull and object from the cache (get and delete).
108
+ #
109
+ # Parameters:
110
+ # +namespace+:: The namespace to get the object from. Use <tt>nil</tt> if global namespace should be used.
111
+ # +key+:: A uniqeue identifier for the object relative to the given namespace.
112
+ def pull(namespace, key)
113
+
114
+ ret = super
115
+ @times.delete(format_times_key(namespace, key, ret)) if not ret.nil?
116
+ ret
117
+
118
+ end
119
+
120
+ def __times_size #:nodoc: Only used by unit test.
121
+
122
+ @times.size
123
+
124
+ end
125
+
126
+ def reset
127
+
128
+ @times = {}
129
+ super
130
+
131
+ end
132
+
133
+ protected
134
+
135
+ def check_expires(expires) #:nodoc:
136
+
137
+ raise TypeError.new("Expected Fixnum or Float as expiration.") if not expires.is_a?(Fixnum) and not expires.is_a?(Float)
138
+
139
+ end
140
+
141
+ def set_expiration(namespace, key, obj, expires) #:nodoc:
142
+
143
+ warning("Expiration time (#{expires}) less than check frequency (#{@config['check_frequency'].to_f}) for key '#{key}'#{" in namespace '#{namespace}'" if namespace}.") if expires.to_f < @config['check_frequency'].to_f
144
+ @times[format_times_key(namespace, key, obj)] = { :time => Time.now + expires, :duration => expires }
145
+
146
+ end
147
+
148
+ def reset_expiration(namespace, key, obj) #:nodoc:
149
+
150
+ times_key = format_times_key(namespace, key, obj)
151
+ @times[times_key][:time] = Time.now + @times[times_key][:duration]
152
+
153
+ end
154
+
155
+ def format_times_key(namespace, key, obj) #:nodoc:
156
+
157
+ if namespace.nil?
158
+
159
+ times_key = "#{key}_#{obj.object_id}"
160
+
161
+ else
162
+
163
+ times_key = "#{namespace}_#{key}_#{obj.object_id}"
164
+
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+
171
+ end
172
+
173
+ end
@@ -0,0 +1,55 @@
1
+ module Boogaloo
2
+
3
+ module Client
4
+
5
+ # A wrapper around DRb for connecting to the boogaloo server.
6
+ #
7
+ # Example usage:
8
+ #
9
+ # boogaloo_cache = Boogaloo::Client::Connection.new('localhost', 7777, true)
10
+ class Connection
11
+
12
+ # Create a new connection to the boogaloo server.
13
+ #
14
+ # Parameters:
15
+ #
16
+ # +host+:: The host name or IP address to bind the socket to.
17
+ # +port+:: The port to bind the socket to.
18
+ # +wrap+:: If true, attempts to access the server when it is offline will result in a _nil_ being returned instead of an exception being raised.
19
+ def initialize(host, port, wrap=false)
20
+
21
+ @wrap = wrap
22
+ druby_str = "druby://#{host}:#{port}"
23
+ DRb.start_service
24
+ @conn = DRbObject.new(nil, druby_str)
25
+
26
+ end
27
+
28
+ # Forwards all method calls to the server.
29
+ def method_missing(msg_id, *a, &b)
30
+
31
+ if @wrap
32
+
33
+ begin
34
+
35
+ return @conn.method_missing(msg_id, a, b)
36
+
37
+ rescue DRb::DRbConnError
38
+
39
+ return nil
40
+
41
+ end
42
+
43
+ else
44
+
45
+ return @conn.method_missing(msg_id, a, b)
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end