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,27 @@
|
|
1
|
+
module Cuboid
|
2
|
+
class State
|
3
|
+
|
4
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
5
|
+
class Options
|
6
|
+
|
7
|
+
def statistics
|
8
|
+
{}
|
9
|
+
end
|
10
|
+
|
11
|
+
def dump( directory )
|
12
|
+
FileUtils.mkdir_p( directory )
|
13
|
+
Cuboid::Options.save( "#{directory}/options" )
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.load( directory )
|
17
|
+
Cuboid::Options.load( "#{directory}/options" )
|
18
|
+
new
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Cuboid
|
2
|
+
module Support::Buffer
|
3
|
+
|
4
|
+
# A buffer implementation which flushes itself when it gets full or a number
|
5
|
+
# of push attempts is reached between flushes.
|
6
|
+
#
|
7
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
8
|
+
class AutoFlush < Base
|
9
|
+
|
10
|
+
attr_reader :max_pushes
|
11
|
+
|
12
|
+
# @param [Integer] max_size
|
13
|
+
# Maximum buffer size -- a flush will be triggered when that limit is
|
14
|
+
# reached.
|
15
|
+
# @param [Integer] max_pushes
|
16
|
+
# Maximum number of pushes between flushes.
|
17
|
+
# @param [#<<, #|, #clear, #size, #empty?] type
|
18
|
+
# Internal storage class to use.
|
19
|
+
def initialize( max_size = nil, max_pushes = nil, type = Array )
|
20
|
+
super( max_size, type )
|
21
|
+
|
22
|
+
@max_pushes = max_pushes
|
23
|
+
@pushes = 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def <<( *args )
|
27
|
+
super( *args )
|
28
|
+
ensure
|
29
|
+
handle_push
|
30
|
+
end
|
31
|
+
|
32
|
+
def batch_push( *args )
|
33
|
+
super( *args )
|
34
|
+
ensure
|
35
|
+
handle_push
|
36
|
+
end
|
37
|
+
|
38
|
+
def flush
|
39
|
+
super
|
40
|
+
ensure
|
41
|
+
@pushes = 0
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def handle_push
|
47
|
+
@pushes += 1
|
48
|
+
flush if flush?
|
49
|
+
end
|
50
|
+
|
51
|
+
def flush?
|
52
|
+
!!(full? || push_limit_reached?)
|
53
|
+
end
|
54
|
+
|
55
|
+
def push_limit_reached?
|
56
|
+
max_pushes && @pushes >= max_pushes
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Cuboid
|
2
|
+
module Support::Buffer
|
3
|
+
|
4
|
+
#
|
5
|
+
# Base buffer class to be extended by more specialised implementation.
|
6
|
+
#
|
7
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
8
|
+
#
|
9
|
+
class Base
|
10
|
+
include Support::Mixins::Observable
|
11
|
+
|
12
|
+
# @!method on_push( &block )
|
13
|
+
# @param [Block] block block to call on {#push}
|
14
|
+
advertise :on_push
|
15
|
+
|
16
|
+
# @!method on_batch_push( &block )
|
17
|
+
# @param [Block] block block to call on {#batch_push}
|
18
|
+
advertise :on_batch_push
|
19
|
+
|
20
|
+
# @!method on_flush( &block )
|
21
|
+
# @param [Block] block block to call on {#flush}
|
22
|
+
advertise :on_flush
|
23
|
+
|
24
|
+
# @return [Integer] Maximum buffer size.
|
25
|
+
attr_reader :max_size
|
26
|
+
|
27
|
+
# @param [Integer] max_size
|
28
|
+
# Maximum buffer size -- won't be enforced.
|
29
|
+
# @param [#<<, #|, #clear, #size, #empty?] type
|
30
|
+
# Internal storage class to use.
|
31
|
+
def initialize( max_size = nil, type = Array )
|
32
|
+
super()
|
33
|
+
@buffer = type.new
|
34
|
+
@max_size = max_size
|
35
|
+
end
|
36
|
+
|
37
|
+
# @note Calls {#on_push} blocks with the given object and pushes an object
|
38
|
+
# to the buffer.
|
39
|
+
#
|
40
|
+
# @param [Object] obj
|
41
|
+
# Object to push.
|
42
|
+
def <<( obj )
|
43
|
+
notify_on_push obj
|
44
|
+
@buffer << obj
|
45
|
+
self
|
46
|
+
end
|
47
|
+
alias :push :<<
|
48
|
+
|
49
|
+
# @note Calls {#on_batch_push} blocks with the given list and merges the
|
50
|
+
# buffer with the contents of a list.
|
51
|
+
#
|
52
|
+
# @param [#|] list
|
53
|
+
# List of objects
|
54
|
+
def batch_push( list )
|
55
|
+
notify_on_batch_push list
|
56
|
+
@buffer |= list
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Integer]
|
61
|
+
# Number of object in the buffer.
|
62
|
+
def size
|
63
|
+
@buffer.size
|
64
|
+
end
|
65
|
+
|
66
|
+
# @return [Bool]
|
67
|
+
# `true` if the buffer is empty, `false` otherwise.
|
68
|
+
def empty?
|
69
|
+
@buffer.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
# @return [Bool]
|
73
|
+
# `true` if the buffer is full, `false` otherwise.
|
74
|
+
def full?
|
75
|
+
!!(max_size && size >= max_size)
|
76
|
+
end
|
77
|
+
|
78
|
+
# @note Calls {#on_flush} blocks with the buffer and then empties it.
|
79
|
+
#
|
80
|
+
# @return current buffer
|
81
|
+
def flush
|
82
|
+
buffer = @buffer.dup
|
83
|
+
notify_on_flush buffer
|
84
|
+
buffer
|
85
|
+
ensure
|
86
|
+
@buffer.clear
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module Cuboid
|
2
|
+
module Support::Cache
|
3
|
+
|
4
|
+
# Base cache implementation -- stores, retrieves and removes entries.
|
5
|
+
#
|
6
|
+
# The cache will be pruned (call {#prune}) upon storage operations, removing
|
7
|
+
# old entries to make room for new ones.
|
8
|
+
#
|
9
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
10
|
+
# @abstract
|
11
|
+
class Base
|
12
|
+
include Support::Mixins::Profiler
|
13
|
+
|
14
|
+
# @return [Integer]
|
15
|
+
# Maximum cache size.
|
16
|
+
attr_reader :max_size
|
17
|
+
|
18
|
+
# @param [Hash] options
|
19
|
+
# @option options [Integer, nil] :size
|
20
|
+
# Maximum size of the cache (must be > 0, `nil` means unlimited).
|
21
|
+
# Once the size of the cache is about to exceed `max_size`, the pruning
|
22
|
+
# phase will be initiated.
|
23
|
+
# # @option options [true, false] :freeze (true)
|
24
|
+
# Whether or not to freeze stored items.
|
25
|
+
def initialize( options = {} )
|
26
|
+
super()
|
27
|
+
|
28
|
+
@options = options
|
29
|
+
@freeze = @options[:freeze].nil? ? true : @options[:freeze]
|
30
|
+
self.max_size = @options[:size]
|
31
|
+
|
32
|
+
@cache = {}
|
33
|
+
@hits = 0
|
34
|
+
@misses = 0
|
35
|
+
@prunings = 0
|
36
|
+
end
|
37
|
+
|
38
|
+
def statistics
|
39
|
+
lookups = @hits + @misses
|
40
|
+
|
41
|
+
{
|
42
|
+
lookups: lookups,
|
43
|
+
hits: @hits,
|
44
|
+
hit_ratio: @hits == 0 ? 0.0 : @hits / Float( lookups ),
|
45
|
+
misses: @misses,
|
46
|
+
miss_ratio: @misses == 0 ? 0.0 : @misses / Float( lookups ),
|
47
|
+
prunings: @prunings,
|
48
|
+
size: size,
|
49
|
+
max_size: max_size
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def max_size=( max )
|
54
|
+
@max_size = if !max
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
fail( 'Maximum size must be greater than 0.' ) if max <= 0
|
58
|
+
max
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Bool]
|
63
|
+
# `true` is there is no size limit, `false` otherwise
|
64
|
+
def uncapped?
|
65
|
+
!capped?
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return [Bool]
|
69
|
+
# `true` is there is a size limit, `false`` otherwise
|
70
|
+
def capped?
|
71
|
+
!!max_size
|
72
|
+
end
|
73
|
+
|
74
|
+
# Uncaps the cache {#max_size} limit
|
75
|
+
def uncap
|
76
|
+
@max_size = nil
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Integer]
|
80
|
+
# Number of entries in the cache.
|
81
|
+
def size
|
82
|
+
@cache.size
|
83
|
+
end
|
84
|
+
|
85
|
+
# Storage method.
|
86
|
+
#
|
87
|
+
# @param [Object] k
|
88
|
+
# Entry key.
|
89
|
+
# @param [Object] v
|
90
|
+
# Object to store.
|
91
|
+
#
|
92
|
+
# @return [Object] `v`
|
93
|
+
def store( k, v )
|
94
|
+
store_with_internal_key( make_key( k ), v )
|
95
|
+
end
|
96
|
+
|
97
|
+
# @see #store
|
98
|
+
def []=( k, v )
|
99
|
+
store( k, v )
|
100
|
+
end
|
101
|
+
|
102
|
+
# Retrieving method.
|
103
|
+
#
|
104
|
+
# @param [Object] k
|
105
|
+
# Entry key.
|
106
|
+
#
|
107
|
+
# @return [Object, nil]
|
108
|
+
# Value for key `k`, `nil` if there is no key `k`.
|
109
|
+
def []( k )
|
110
|
+
get_with_internal_key( make_key( k ) )
|
111
|
+
end
|
112
|
+
|
113
|
+
# @note If key `k` exists, its corresponding value will be returned.
|
114
|
+
# If not, the return value of `block` will be assigned to key `k` and that
|
115
|
+
# value will be returned.
|
116
|
+
#
|
117
|
+
# @param [Object] k
|
118
|
+
# Entry key.
|
119
|
+
#
|
120
|
+
# @return [Object]
|
121
|
+
# Value for key `k` or `block.call` if key `k` does not exist.
|
122
|
+
def fetch( k, &block )
|
123
|
+
k = make_key( k )
|
124
|
+
|
125
|
+
if @cache.include?( k )
|
126
|
+
get_with_internal_key( k )
|
127
|
+
else
|
128
|
+
@misses += 1
|
129
|
+
store_with_internal_key( k, profile_proc( &block ) )
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [Bool]
|
134
|
+
# `true` if cache includes an entry for key `k`, false otherwise.
|
135
|
+
def include?( k )
|
136
|
+
@cache.include?( make_key( k ) )
|
137
|
+
end
|
138
|
+
|
139
|
+
# @return [Bool]
|
140
|
+
# `true` if cache is empty, false otherwise.
|
141
|
+
def empty?
|
142
|
+
@cache.empty?
|
143
|
+
end
|
144
|
+
|
145
|
+
# @return [Bool]
|
146
|
+
# `true` if cache is not empty, `false` otherwise.
|
147
|
+
def any?
|
148
|
+
!empty?
|
149
|
+
end
|
150
|
+
|
151
|
+
# Removes entry with key `k` from the cache.
|
152
|
+
#
|
153
|
+
# @param [Object] k
|
154
|
+
# Key.
|
155
|
+
#
|
156
|
+
# @return [Object, nil]
|
157
|
+
# Value for key `k`, `nil` if there is no key `k`.
|
158
|
+
def delete( k )
|
159
|
+
@cache.delete( make_key( k ) )
|
160
|
+
end
|
161
|
+
|
162
|
+
# Clears/empties the cache.
|
163
|
+
def clear
|
164
|
+
@cache.clear
|
165
|
+
end
|
166
|
+
|
167
|
+
def ==( other )
|
168
|
+
hash == other.hash
|
169
|
+
end
|
170
|
+
|
171
|
+
def hash
|
172
|
+
@cache.hash
|
173
|
+
end
|
174
|
+
|
175
|
+
def dup
|
176
|
+
self.class.new( @options.dup ).tap { |h| h.cache = @cache.dup }
|
177
|
+
end
|
178
|
+
|
179
|
+
protected
|
180
|
+
|
181
|
+
def cache=( c )
|
182
|
+
@cache = c
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def store_with_internal_key( k, v )
|
188
|
+
while capped? && (size > max_size - 1)
|
189
|
+
prune
|
190
|
+
@prunings += 1
|
191
|
+
end
|
192
|
+
|
193
|
+
_store( k, v )
|
194
|
+
end
|
195
|
+
|
196
|
+
def _store( k, v )
|
197
|
+
@cache[k] = @freeze ? v.freeze : v
|
198
|
+
end
|
199
|
+
|
200
|
+
def get_with_internal_key( k )
|
201
|
+
if (r = @cache[k])
|
202
|
+
@hits += 1
|
203
|
+
else
|
204
|
+
@misses += 1
|
205
|
+
end
|
206
|
+
r
|
207
|
+
end
|
208
|
+
|
209
|
+
def make_key( k )
|
210
|
+
k.hash
|
211
|
+
end
|
212
|
+
|
213
|
+
def cache
|
214
|
+
@cache
|
215
|
+
end
|
216
|
+
|
217
|
+
# Called to make room when the cache is about to reach its maximum size.
|
218
|
+
#
|
219
|
+
# @abstract
|
220
|
+
def prune
|
221
|
+
fail NotImplementedError
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Cuboid
|
2
|
+
module Support::Cache
|
3
|
+
|
4
|
+
# Least Cost Replacement cache implementation.
|
5
|
+
#
|
6
|
+
# Maintains 3 cost classes (low, medium, high) ) and discards entries from the
|
7
|
+
# lowest cost classes in order to make room for new ones.
|
8
|
+
#
|
9
|
+
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
10
|
+
class LeastCostReplacement < Base
|
11
|
+
|
12
|
+
VALID_COSTS = [ :low, :medium, :high ]
|
13
|
+
|
14
|
+
# @see Cuboid::Cache::Base#initialize
|
15
|
+
def initialize( * )
|
16
|
+
super
|
17
|
+
reset_costs
|
18
|
+
end
|
19
|
+
|
20
|
+
# Storage method
|
21
|
+
#
|
22
|
+
# @param [Object] k
|
23
|
+
# Entry key.
|
24
|
+
# @param [Object] v
|
25
|
+
# Object to store.
|
26
|
+
# @param [Symbol] cost
|
27
|
+
#
|
28
|
+
# @return [Object] `v`
|
29
|
+
#
|
30
|
+
# @see VALID_COSTS
|
31
|
+
def store( k, v, cost = :low )
|
32
|
+
fail( "invalid cost: #{cost}" ) if !valid_cost?( cost )
|
33
|
+
|
34
|
+
super( k, v )
|
35
|
+
ensure
|
36
|
+
@costs[cost] << k
|
37
|
+
end
|
38
|
+
|
39
|
+
# @see Cuboid::Cache::Base#clear
|
40
|
+
def clear
|
41
|
+
super
|
42
|
+
ensure
|
43
|
+
reset_costs
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def reset_costs
|
49
|
+
@costs = {}
|
50
|
+
VALID_COSTS.each { |c| @costs[c] = [] }
|
51
|
+
end
|
52
|
+
|
53
|
+
def valid_cost?( cost )
|
54
|
+
VALID_COSTS.include?( cost )
|
55
|
+
end
|
56
|
+
|
57
|
+
def candidate_from_cost_class( cost_class )
|
58
|
+
return if (costs = @costs[cost_class]).empty?
|
59
|
+
costs.delete_at( rand( costs.size ) )
|
60
|
+
end
|
61
|
+
|
62
|
+
def prune_candidate
|
63
|
+
VALID_COSTS.each do |cost|
|
64
|
+
if c = candidate_from_cost_class( cost )
|
65
|
+
return c
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def prune
|
71
|
+
delete( prune_candidate )
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|