cuboid 0.0.0 → 0.0.1alpha
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +0 -0
- data/Gemfile +20 -5
- data/LICENSE.md +22 -0
- data/README.md +158 -19
- data/Rakefile +56 -3
- data/config/paths.yml +15 -0
- data/cuboid.gemspec +61 -23
- data/lib/cuboid.rb +96 -4
- data/lib/cuboid/application.rb +326 -0
- data/lib/cuboid/application/parts/data.rb +18 -0
- data/lib/cuboid/application/parts/report.rb +29 -0
- data/lib/cuboid/application/parts/state.rb +274 -0
- data/lib/cuboid/application/runtime.rb +25 -0
- data/lib/cuboid/banner.rb +13 -0
- data/lib/cuboid/data.rb +86 -0
- data/lib/cuboid/data/application.rb +52 -0
- data/lib/cuboid/error.rb +9 -0
- data/lib/cuboid/option_group.rb +129 -0
- data/lib/cuboid/option_groups.rb +8 -0
- data/lib/cuboid/option_groups/datastore.rb +23 -0
- data/lib/cuboid/option_groups/dispatcher.rb +38 -0
- data/lib/cuboid/option_groups/output.rb +14 -0
- data/lib/cuboid/option_groups/paths.rb +184 -0
- data/lib/cuboid/option_groups/report.rb +39 -0
- data/lib/cuboid/option_groups/rpc.rb +105 -0
- data/lib/cuboid/option_groups/scheduler.rb +27 -0
- data/lib/cuboid/option_groups/snapshot.rb +13 -0
- data/lib/cuboid/option_groups/system.rb +10 -0
- data/lib/cuboid/options.rb +254 -0
- data/lib/cuboid/processes.rb +13 -0
- data/lib/cuboid/processes/dispatchers.rb +140 -0
- data/lib/cuboid/processes/executables/base.rb +54 -0
- data/lib/cuboid/processes/executables/dispatcher.rb +5 -0
- data/lib/cuboid/processes/executables/instance.rb +12 -0
- data/lib/cuboid/processes/executables/rest_service.rb +13 -0
- data/lib/cuboid/processes/executables/scheduler.rb +5 -0
- data/lib/cuboid/processes/helpers.rb +4 -0
- data/lib/cuboid/processes/helpers/dispatchers.rb +23 -0
- data/lib/cuboid/processes/helpers/instances.rb +39 -0
- data/lib/cuboid/processes/helpers/processes.rb +23 -0
- data/lib/cuboid/processes/helpers/schedulers.rb +23 -0
- data/lib/cuboid/processes/instances.rb +203 -0
- data/lib/cuboid/processes/manager.rb +262 -0
- data/lib/cuboid/processes/schedulers.rb +128 -0
- data/lib/cuboid/report.rb +220 -0
- data/lib/cuboid/rest/server.rb +165 -0
- data/lib/cuboid/rest/server/instance_helpers.rb +99 -0
- data/lib/cuboid/rest/server/routes/dispatcher.rb +41 -0
- data/lib/cuboid/rest/server/routes/grid.rb +41 -0
- data/lib/cuboid/rest/server/routes/instances.rb +131 -0
- data/lib/cuboid/rest/server/routes/scheduler.rb +140 -0
- data/lib/cuboid/rpc/client.rb +3 -0
- data/lib/cuboid/rpc/client/base.rb +58 -0
- data/lib/cuboid/rpc/client/dispatcher.rb +58 -0
- data/lib/cuboid/rpc/client/instance.rb +100 -0
- data/lib/cuboid/rpc/client/instance/service.rb +37 -0
- data/lib/cuboid/rpc/client/scheduler.rb +46 -0
- data/lib/cuboid/rpc/serializer.rb +92 -0
- data/lib/cuboid/rpc/server/active_options.rb +38 -0
- data/lib/cuboid/rpc/server/application_wrapper.rb +138 -0
- data/lib/cuboid/rpc/server/base.rb +63 -0
- data/lib/cuboid/rpc/server/dispatcher.rb +317 -0
- data/lib/cuboid/rpc/server/dispatcher/node.rb +247 -0
- data/lib/cuboid/rpc/server/dispatcher/service.rb +145 -0
- data/lib/cuboid/rpc/server/instance.rb +338 -0
- data/lib/cuboid/rpc/server/output.rb +92 -0
- data/lib/cuboid/rpc/server/scheduler.rb +482 -0
- data/lib/cuboid/ruby.rb +4 -0
- data/lib/cuboid/ruby/array.rb +17 -0
- data/lib/cuboid/ruby/hash.rb +41 -0
- data/lib/cuboid/ruby/object.rb +32 -0
- data/lib/cuboid/snapshot.rb +186 -0
- data/lib/cuboid/state.rb +94 -0
- data/lib/cuboid/state/application.rb +309 -0
- data/lib/cuboid/state/options.rb +27 -0
- data/lib/cuboid/support.rb +11 -0
- data/lib/cuboid/support/buffer.rb +3 -0
- data/lib/cuboid/support/buffer/autoflush.rb +61 -0
- data/lib/cuboid/support/buffer/base.rb +91 -0
- data/lib/cuboid/support/cache.rb +7 -0
- data/lib/cuboid/support/cache/base.rb +226 -0
- data/lib/cuboid/support/cache/least_cost_replacement.rb +77 -0
- data/lib/cuboid/support/cache/least_recently_pushed.rb +21 -0
- data/lib/cuboid/support/cache/least_recently_used.rb +31 -0
- data/lib/cuboid/support/cache/preference.rb +31 -0
- data/lib/cuboid/support/cache/random_replacement.rb +20 -0
- data/lib/cuboid/support/crypto.rb +2 -0
- data/lib/cuboid/support/crypto/rsa_aes_cbc.rb +86 -0
- data/lib/cuboid/support/database.rb +5 -0
- data/lib/cuboid/support/database/base.rb +177 -0
- data/lib/cuboid/support/database/categorized_queue.rb +195 -0
- data/lib/cuboid/support/database/hash.rb +300 -0
- data/lib/cuboid/support/database/queue.rb +149 -0
- data/lib/cuboid/support/filter.rb +3 -0
- data/lib/cuboid/support/filter/base.rb +110 -0
- data/lib/cuboid/support/filter/set.rb +29 -0
- data/lib/cuboid/support/glob.rb +27 -0
- data/lib/cuboid/support/mixins.rb +8 -0
- data/lib/cuboid/support/mixins/observable.rb +99 -0
- data/lib/cuboid/support/mixins/parts.rb +20 -0
- data/lib/cuboid/support/mixins/profiler.rb +93 -0
- data/lib/cuboid/support/mixins/spec_instances.rb +65 -0
- data/lib/cuboid/support/mixins/terminal.rb +57 -0
- data/lib/cuboid/system.rb +119 -0
- data/lib/cuboid/system/platforms.rb +84 -0
- data/lib/cuboid/system/platforms/linux.rb +26 -0
- data/lib/cuboid/system/platforms/mixins/unix.rb +46 -0
- data/lib/cuboid/system/platforms/osx.rb +25 -0
- data/lib/cuboid/system/platforms/windows.rb +81 -0
- data/lib/cuboid/system/slots.rb +143 -0
- data/lib/cuboid/ui/output.rb +52 -0
- data/lib/cuboid/ui/output_interface.rb +43 -0
- data/lib/cuboid/ui/output_interface/abstract.rb +68 -0
- data/lib/cuboid/ui/output_interface/controls.rb +84 -0
- data/lib/cuboid/ui/output_interface/error_logging.rb +119 -0
- data/lib/cuboid/ui/output_interface/implemented.rb +58 -0
- data/lib/cuboid/ui/output_interface/personalization.rb +62 -0
- data/lib/cuboid/utilities.rb +155 -0
- data/lib/cuboid/version.rb +4 -3
- data/lib/version +1 -0
- data/logs/placeholder +0 -0
- data/spec/cuboid/application/parts/data_spec.rb +12 -0
- data/spec/cuboid/application/parts/report_spec.rb +6 -0
- data/spec/cuboid/application/parts/state_spec.rb +192 -0
- data/spec/cuboid/application/runtime_spec.rb +21 -0
- data/spec/cuboid/application_spec.rb +37 -0
- data/spec/cuboid/data/application_spec.rb +22 -0
- data/spec/cuboid/data_spec.rb +47 -0
- data/spec/cuboid/error_spec.rb +23 -0
- data/spec/cuboid/option_groups/datastore_spec.rb +54 -0
- data/spec/cuboid/option_groups/dispatcher_spec.rb +12 -0
- data/spec/cuboid/option_groups/output_spec.rb +11 -0
- data/spec/cuboid/option_groups/paths_spec.rb +184 -0
- data/spec/cuboid/option_groups/report_spec.rb +26 -0
- data/spec/cuboid/option_groups/rpc_spec.rb +53 -0
- data/spec/cuboid/option_groups/snapshot_spec.rb +26 -0
- data/spec/cuboid/option_groups/system.rb +12 -0
- data/spec/cuboid/options_spec.rb +218 -0
- data/spec/cuboid/report_spec.rb +221 -0
- data/spec/cuboid/rest/server_spec.rb +1205 -0
- data/spec/cuboid/rpc/client/base_spec.rb +151 -0
- data/spec/cuboid/rpc/client/dispatcher_spec.rb +13 -0
- data/spec/cuboid/rpc/client/instance_spec.rb +38 -0
- data/spec/cuboid/rpc/server/active_options_spec.rb +21 -0
- data/spec/cuboid/rpc/server/base_spec.rb +60 -0
- data/spec/cuboid/rpc/server/dispatcher/node_spec.rb +222 -0
- data/spec/cuboid/rpc/server/dispatcher/service_spec.rb +112 -0
- data/spec/cuboid/rpc/server/dispatcher_spec.rb +317 -0
- data/spec/cuboid/rpc/server/instance_spec.rb +307 -0
- data/spec/cuboid/rpc/server/output_spec.rb +32 -0
- data/spec/cuboid/rpc/server/scheduler_spec.rb +400 -0
- data/spec/cuboid/ruby/array_spec.rb +77 -0
- data/spec/cuboid/ruby/hash_spec.rb +63 -0
- data/spec/cuboid/ruby/object_spec.rb +22 -0
- data/spec/cuboid/snapshot_spec.rb +123 -0
- data/spec/cuboid/state/application_spec.rb +538 -0
- data/spec/cuboid/state/options_spec.rb +37 -0
- data/spec/cuboid/state_spec.rb +53 -0
- data/spec/cuboid/support/buffer/autoflush_spec.rb +78 -0
- data/spec/cuboid/support/buffer/base_spec.rb +193 -0
- data/spec/cuboid/support/cache/least_cost_replacement_spec.rb +61 -0
- data/spec/cuboid/support/cache/least_recently_pushed_spec.rb +90 -0
- data/spec/cuboid/support/cache/least_recently_used_spec.rb +80 -0
- data/spec/cuboid/support/cache/preference_spec.rb +37 -0
- data/spec/cuboid/support/cache/random_replacement_spec.rb +42 -0
- data/spec/cuboid/support/crypto/rsa_aes_cbc_spec.rb +28 -0
- data/spec/cuboid/support/database/categorized_queue_spec.rb +327 -0
- data/spec/cuboid/support/database/hash_spec.rb +204 -0
- data/spec/cuboid/support/database/scheduler_spec.rb +325 -0
- data/spec/cuboid/support/filter/set_spec.rb +19 -0
- data/spec/cuboid/support/glob_spec.rb +75 -0
- data/spec/cuboid/support/mixins/observable_spec.rb +95 -0
- data/spec/cuboid/system/platforms/linux_spec.rb +31 -0
- data/spec/cuboid/system/platforms/osx_spec.rb +32 -0
- data/spec/cuboid/system/platforms/windows_spec.rb +41 -0
- data/spec/cuboid/system/slots_spec.rb +202 -0
- data/spec/cuboid/system_spec.rb +105 -0
- data/spec/cuboid/utilities_spec.rb +131 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/factories/placeholder +0 -0
- data/spec/support/factories/scan_report.rb +18 -0
- data/spec/support/fixtures/empty/placeholder +0 -0
- data/spec/support/fixtures/executables/node.rb +50 -0
- data/spec/support/fixtures/mock_app.rb +61 -0
- data/spec/support/fixtures/mock_app/test_service.rb +64 -0
- data/spec/support/fixtures/services/echo.rb +64 -0
- data/spec/support/helpers/framework.rb +3 -0
- data/spec/support/helpers/matchers.rb +5 -0
- data/spec/support/helpers/misc.rb +3 -0
- data/spec/support/helpers/paths.rb +15 -0
- data/spec/support/helpers/request_helpers.rb +38 -0
- data/spec/support/helpers/requires.rb +8 -0
- data/spec/support/helpers/resets.rb +52 -0
- data/spec/support/helpers/web_server.rb +15 -0
- data/spec/support/lib/factory.rb +107 -0
- data/spec/support/lib/web_server_client.rb +41 -0
- data/spec/support/lib/web_server_dispatcher.rb +25 -0
- data/spec/support/lib/web_server_manager.rb +118 -0
- data/spec/support/logs/placeholder +0 -0
- data/spec/support/pems/cacert.pem +37 -0
- data/spec/support/pems/client/cert.pem +37 -0
- data/spec/support/pems/client/foo-cert.pem +39 -0
- data/spec/support/pems/client/foo-key.pem +51 -0
- data/spec/support/pems/client/key.pem +51 -0
- data/spec/support/pems/server/cert.pem +37 -0
- data/spec/support/pems/server/key.pem +51 -0
- data/spec/support/reports/placeholder +0 -0
- data/spec/support/shared/application.rb +10 -0
- data/spec/support/shared/component.rb +31 -0
- data/spec/support/shared/component/options/base.rb +187 -0
- data/spec/support/shared/option_group.rb +98 -0
- data/spec/support/shared/support/cache.rb +419 -0
- data/spec/support/shared/support/filter.rb +143 -0
- data/spec/support/shared/system/platforms/base.rb +25 -0
- data/spec/support/shared/system/platforms/mixins/unix.rb +37 -0
- data/spec/support/snapshots/placeholder +0 -0
- metadata +566 -21
- data/.gitignore +0 -8
- data/bin/console +0 -15
- data/bin/setup +0 -8
@@ -0,0 +1,300 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module Cuboid
|
4
|
+
module Support::Database
|
5
|
+
|
6
|
+
# Flat-file Hash implementation
|
7
|
+
#
|
8
|
+
# Behaves pretty much like a Ruby Hash however it transparently serializes and
|
9
|
+
# saves its values to the file-system under the OS's temp directory.
|
10
|
+
#
|
11
|
+
# It's not interchangeable with Ruby's Hash as it lacks a lot of the
|
12
|
+
# stdlib methods.
|
13
|
+
#
|
14
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
15
|
+
# @version 0.1
|
16
|
+
class Hash < Base
|
17
|
+
|
18
|
+
# @see Cuboid::Database::Base#initialize
|
19
|
+
def initialize( *args )
|
20
|
+
super( *args )
|
21
|
+
|
22
|
+
# holds the internal representation of the Hash
|
23
|
+
# same keys as self but the values are actually pointing to filepaths
|
24
|
+
# where the real values are being stores
|
25
|
+
@h = ::Hash.new
|
26
|
+
|
27
|
+
# holds a key-value pair of self with digests as values
|
28
|
+
# in order to allow comparisons without requiring to load
|
29
|
+
# the actual values from their files.
|
30
|
+
@eql_h = ::Hash.new
|
31
|
+
end
|
32
|
+
|
33
|
+
# Associates the given value with the given key.
|
34
|
+
#
|
35
|
+
# @param [Object] k
|
36
|
+
# Key.
|
37
|
+
# @param [Object] v
|
38
|
+
# Value.
|
39
|
+
#
|
40
|
+
# @return [Object]
|
41
|
+
# `v`.
|
42
|
+
def []=( k, v )
|
43
|
+
@h[k] = dump( v ) do |serialized|
|
44
|
+
@eql_h[k] = eql_hash( serialized )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
alias :store :[]=
|
48
|
+
|
49
|
+
# @param [Obj] k key
|
50
|
+
#
|
51
|
+
# @return [Object]
|
52
|
+
# Object corresponding to the key object, `nil` otherwise.
|
53
|
+
def []( k )
|
54
|
+
load( @h[k] ) if @h[k]
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [Object] k
|
58
|
+
# Key.
|
59
|
+
#
|
60
|
+
# @return [Array]
|
61
|
+
# Array containing the given key and its value.
|
62
|
+
def assoc( k )
|
63
|
+
return if !@h[k]
|
64
|
+
[ k, self[k] ]
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param [Object] v
|
68
|
+
# Value.
|
69
|
+
#
|
70
|
+
# @return [Array]
|
71
|
+
# Array containing the key for the given value and that value.
|
72
|
+
def rassoc( v )
|
73
|
+
return if !value?( v )
|
74
|
+
[ key( v ), v ]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Removes an entry by key and returns its value.
|
78
|
+
#
|
79
|
+
# If the key doesn't exist and a block has been provided it's passed
|
80
|
+
# the key and the method returns the result of that block.
|
81
|
+
#
|
82
|
+
# @param [Object] k
|
83
|
+
# Key.
|
84
|
+
#
|
85
|
+
# @return [Object]
|
86
|
+
def delete( k, &block )
|
87
|
+
if @h[k]
|
88
|
+
obj = load_and_delete_file( @h[k] )
|
89
|
+
@h.delete( k )
|
90
|
+
@eql_h.delete( k )
|
91
|
+
return obj
|
92
|
+
else
|
93
|
+
block.call( k ) if block_given?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Removes the first key-value pair from the hash and returns it as a array,
|
98
|
+
#
|
99
|
+
# @return [Array]
|
100
|
+
def shift
|
101
|
+
k, v = @h.first
|
102
|
+
[ k, delete( k ) ]
|
103
|
+
end
|
104
|
+
|
105
|
+
# Calls block with each key-value pair.
|
106
|
+
#
|
107
|
+
# If a block has been given it retuns self.
|
108
|
+
# If no block has been given it returns an enumerator.
|
109
|
+
#
|
110
|
+
# @param [Proc] block
|
111
|
+
def each( &block )
|
112
|
+
if block_given?
|
113
|
+
@h.each { |k, v| block.call( [ k, self[k] ] ) }
|
114
|
+
self
|
115
|
+
else
|
116
|
+
enum_for( :each )
|
117
|
+
end
|
118
|
+
end
|
119
|
+
alias :each_pair :each
|
120
|
+
|
121
|
+
# Calls block with each key.
|
122
|
+
#
|
123
|
+
# If a block has been given it returns self.
|
124
|
+
# If no block has been given it returns an enumerator.
|
125
|
+
#
|
126
|
+
# @param [Proc] block
|
127
|
+
def each_key( &block )
|
128
|
+
if block_given?
|
129
|
+
@h.each_key( &block )
|
130
|
+
self
|
131
|
+
else
|
132
|
+
enum_for( :each_key )
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Calls block with each value.
|
137
|
+
#
|
138
|
+
# If a block has been given it returns `self`.
|
139
|
+
# If no block has been given it returns an enumerator.
|
140
|
+
#
|
141
|
+
# @param [Proc] block
|
142
|
+
def each_value( &block )
|
143
|
+
if block_given?
|
144
|
+
@h.keys.each { |k| block.call( self[k] ) }
|
145
|
+
self
|
146
|
+
else
|
147
|
+
enum_for( :each_value )
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# @return [Array]
|
152
|
+
# Keys.
|
153
|
+
def keys
|
154
|
+
@h.keys
|
155
|
+
end
|
156
|
+
|
157
|
+
# @param [Object] val
|
158
|
+
#
|
159
|
+
# @return [Object] key
|
160
|
+
# key for the given value.
|
161
|
+
def key( val )
|
162
|
+
return if !value?( val )
|
163
|
+
each { |k, v| return k if val == self[k] }
|
164
|
+
nil
|
165
|
+
end
|
166
|
+
|
167
|
+
# @return [Array]
|
168
|
+
# Values.
|
169
|
+
def values
|
170
|
+
each_value.to_a
|
171
|
+
end
|
172
|
+
|
173
|
+
# @return [Bool]
|
174
|
+
# `true` if the given key exists in the hash, `false` otherwise.
|
175
|
+
def include?( k )
|
176
|
+
@h.include?( k )
|
177
|
+
end
|
178
|
+
alias :member? :include?
|
179
|
+
alias :key? :include?
|
180
|
+
alias :has_key? :include?
|
181
|
+
|
182
|
+
# @return [Bool]
|
183
|
+
# `true` if the given value exists in the hash, `false` otherwise.
|
184
|
+
def value?( v )
|
185
|
+
each_value { |val| return true if val == v }
|
186
|
+
false
|
187
|
+
end
|
188
|
+
|
189
|
+
# Merges the contents of self with the contents of the given hash and
|
190
|
+
# returns them in a new object.
|
191
|
+
#
|
192
|
+
# @param [Hash] h
|
193
|
+
#
|
194
|
+
# @return [Cuboid::Database::Set]
|
195
|
+
def merge( h )
|
196
|
+
self.class.new( @options ).merge!( self ).merge!( h )
|
197
|
+
end
|
198
|
+
|
199
|
+
# Merges self with the contents of the given hash and returns self.
|
200
|
+
#
|
201
|
+
# If the given Hash is of the same type as self then the values will
|
202
|
+
# not be loaded during the merge in order to keep memory usage down.
|
203
|
+
#
|
204
|
+
# If the given Hash is any other kind of object it will be coerced
|
205
|
+
# to a Hash by calling 'to_hash' on it and the merging it with self.
|
206
|
+
#
|
207
|
+
# @param [Hash] h
|
208
|
+
def merge!( h )
|
209
|
+
if !h.is_a?( self.class )
|
210
|
+
h.to_hash.each do |k, v|
|
211
|
+
delete( k ) if @h.include?( k )
|
212
|
+
self[k] = v
|
213
|
+
end
|
214
|
+
else
|
215
|
+
h._internal.each do |k, v|
|
216
|
+
delete( k ) if @h.include?( k )
|
217
|
+
@h[k] = v
|
218
|
+
end
|
219
|
+
@eql_h.merge!( h._eql_h )
|
220
|
+
end
|
221
|
+
self
|
222
|
+
end
|
223
|
+
alias :update :merge!
|
224
|
+
|
225
|
+
# @return [Hash]
|
226
|
+
# `self` as Ruby Hash
|
227
|
+
def to_hash
|
228
|
+
h = {}
|
229
|
+
each { |k, v| h[k] = v }
|
230
|
+
h
|
231
|
+
end
|
232
|
+
alias :to_h :to_hash
|
233
|
+
|
234
|
+
# @return [Array]
|
235
|
+
# `self` as a Ruby Array.
|
236
|
+
def to_a
|
237
|
+
to_hash.to_a
|
238
|
+
end
|
239
|
+
|
240
|
+
# @return [Integer]
|
241
|
+
# Number of objects.
|
242
|
+
def size
|
243
|
+
@h.size
|
244
|
+
end
|
245
|
+
alias :length :size
|
246
|
+
|
247
|
+
# @return [Bool]
|
248
|
+
# `true` if the Hash if empty, `false` otherwise.
|
249
|
+
def empty?
|
250
|
+
@h.empty?
|
251
|
+
end
|
252
|
+
|
253
|
+
# Removes all objects.
|
254
|
+
def clear
|
255
|
+
@h.values.each { |filepath| delete_file( filepath ) }
|
256
|
+
@h.clear
|
257
|
+
end
|
258
|
+
|
259
|
+
# @note If the given hash is not of the same type as self it will be coerced
|
260
|
+
# to a Ruby Hash by calling 'to_hash' on it.
|
261
|
+
#
|
262
|
+
# @return [Bool]
|
263
|
+
# `true` if self and the given hash contain the same key-pair values.
|
264
|
+
def ==( h )
|
265
|
+
if !h.is_a?( self.class )
|
266
|
+
eql = {}
|
267
|
+
h.to_hash.each { |k, v| eql[k] = eql_hash( serialize( v ) ) }
|
268
|
+
@eql_h == eql
|
269
|
+
else
|
270
|
+
@eql_h == h._eql_h
|
271
|
+
end
|
272
|
+
end
|
273
|
+
alias :eql? :==
|
274
|
+
|
275
|
+
# It will return a Ruby Hash with the same values as self but
|
276
|
+
# with filepaths as values (pointing to the files that store them).
|
277
|
+
#
|
278
|
+
# This is used for efficient merging, i.e. without requiring to load
|
279
|
+
# the actual values when merging 2 objects.
|
280
|
+
#
|
281
|
+
# @return [Hash]
|
282
|
+
# Internal representation of `self`.
|
283
|
+
def _internal
|
284
|
+
@h.dup
|
285
|
+
end
|
286
|
+
|
287
|
+
def _eql_h
|
288
|
+
@eql_h.dup
|
289
|
+
end
|
290
|
+
|
291
|
+
private
|
292
|
+
|
293
|
+
def eql_hash( str )
|
294
|
+
Digest::SHA1.hexdigest( str )
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
module Cuboid
|
2
|
+
module Support::Database
|
3
|
+
|
4
|
+
# Flat-file Scheduler implementation
|
5
|
+
#
|
6
|
+
# Behaves pretty much like a Ruby Scheduler however it transparently serializes and
|
7
|
+
# saves its entries to the file-system under the OS's temp directory **after**
|
8
|
+
# a specified {#max_buffer_size} (for in-memory entries) has been exceeded.
|
9
|
+
#
|
10
|
+
# It's pretty useful when you want to reduce memory footprint without
|
11
|
+
# having to refactor any code since it behaves just like a Ruby Scheduler
|
12
|
+
# implementation.
|
13
|
+
#
|
14
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
15
|
+
class Queue < Base
|
16
|
+
|
17
|
+
# Default {#max_buffer_size}.
|
18
|
+
DEFAULT_MAX_BUFFER_SIZE = 100
|
19
|
+
|
20
|
+
# @return [Integer]
|
21
|
+
# How many entries to keep in memory before starting to off-load to disk.
|
22
|
+
attr_accessor :max_buffer_size
|
23
|
+
|
24
|
+
# @return [Array<Object>]
|
25
|
+
# Objects stored in the memory buffer.
|
26
|
+
attr_reader :buffer
|
27
|
+
|
28
|
+
# @return [Array<String>]
|
29
|
+
# Paths to files stored to disk.
|
30
|
+
attr_reader :disk
|
31
|
+
|
32
|
+
# @see Cuboid::Database::Base#initialize
|
33
|
+
def initialize( options = {} )
|
34
|
+
super( options )
|
35
|
+
|
36
|
+
@max_buffer_size = options[:max_buffer_size] || DEFAULT_MAX_BUFFER_SIZE
|
37
|
+
|
38
|
+
@disk = []
|
39
|
+
@buffer = []
|
40
|
+
@waiting = []
|
41
|
+
@mutex = Mutex.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# @note Defaults to {DEFAULT_MAX_BUFFER_SIZE}.
|
45
|
+
#
|
46
|
+
# @return [Integer]
|
47
|
+
# How many entries to keep in memory before starting to off-load to disk.
|
48
|
+
def max_buffer_size
|
49
|
+
@max_buffer_size
|
50
|
+
end
|
51
|
+
|
52
|
+
# @param [Object] obj
|
53
|
+
# Object to add to the queue.
|
54
|
+
def <<( obj )
|
55
|
+
synchronize do
|
56
|
+
if @buffer.size < max_buffer_size
|
57
|
+
@buffer << obj
|
58
|
+
else
|
59
|
+
@disk << dump( obj )
|
60
|
+
end
|
61
|
+
|
62
|
+
begin
|
63
|
+
t = @waiting.shift
|
64
|
+
t.wakeup if t
|
65
|
+
rescue ThreadError
|
66
|
+
retry
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
alias :push :<<
|
71
|
+
alias :enq :<<
|
72
|
+
|
73
|
+
# @return [Object]
|
74
|
+
# Removes an object from the queue and returns it.
|
75
|
+
def pop( non_block = false )
|
76
|
+
synchronize do
|
77
|
+
loop do
|
78
|
+
if internal_empty?
|
79
|
+
raise ThreadError, 'queue empty' if non_block
|
80
|
+
@waiting.push Thread.current
|
81
|
+
@mutex.sleep
|
82
|
+
else
|
83
|
+
return @buffer.shift if !@buffer.empty?
|
84
|
+
return load_and_delete_file( @disk.shift )
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
alias :deq :pop
|
90
|
+
alias :shift :pop
|
91
|
+
|
92
|
+
# @return [Integer]
|
93
|
+
# Size of the queue, the number of objects it currently holds.
|
94
|
+
def size
|
95
|
+
buffer_size + disk_size
|
96
|
+
end
|
97
|
+
alias :length :size
|
98
|
+
|
99
|
+
def free_buffer_size
|
100
|
+
max_buffer_size - buffer_size
|
101
|
+
end
|
102
|
+
|
103
|
+
def buffer_size
|
104
|
+
@buffer.size
|
105
|
+
end
|
106
|
+
|
107
|
+
def disk_size
|
108
|
+
@disk.size
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Bool]
|
112
|
+
# `true` if the queue if empty, `false` otherwise.
|
113
|
+
def empty?
|
114
|
+
synchronize do
|
115
|
+
internal_empty?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Removes all objects from the queue.
|
120
|
+
def clear
|
121
|
+
synchronize do
|
122
|
+
@buffer.clear
|
123
|
+
|
124
|
+
while !@disk.empty?
|
125
|
+
path = @disk.pop
|
126
|
+
next if !path
|
127
|
+
delete_file path
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def num_waiting
|
133
|
+
@waiting.size
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
def internal_empty?
|
139
|
+
@buffer.empty? && @disk.empty?
|
140
|
+
end
|
141
|
+
|
142
|
+
def synchronize( &block )
|
143
|
+
@mutex.synchronize( &block )
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|