woolen_common 0.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 (86) hide show
  1. checksums.yaml +15 -0
  2. data/README.md +31 -0
  3. data/ext/woolen_common/extconf.rb +26 -0
  4. data/ext/woolen_common/linux.h +3 -0
  5. data/ext/woolen_common/win.c +18 -0
  6. data/ext/woolen_common/win.h +4 -0
  7. data/ext/woolen_common/win/puts_color.c +139 -0
  8. data/ext/woolen_common/win/puts_color.h +5 -0
  9. data/ext/woolen_common/woolen_common.c +20 -0
  10. data/ext/woolen_common/woolen_common.h +7 -0
  11. data/lib/woolen_common.rb +39 -0
  12. data/lib/woolen_common/abstract_middleware/builder.rb +138 -0
  13. data/lib/woolen_common/abstract_middleware/map_cfg_manager.rb +52 -0
  14. data/lib/woolen_common/abstract_middleware/runner.rb +72 -0
  15. data/lib/woolen_common/action_pool_proxy.rb +28 -0
  16. data/lib/woolen_common/actionpool.rb +10 -0
  17. data/lib/woolen_common/actionpool/pool.rb +295 -0
  18. data/lib/woolen_common/actionpool/queue.rb +41 -0
  19. data/lib/woolen_common/actionpool/thread.rb +181 -0
  20. data/lib/woolen_common/addr_helper.rb +93 -0
  21. data/lib/woolen_common/cache.rb +305 -0
  22. data/lib/woolen_common/common_helper.rb +42 -0
  23. data/lib/woolen_common/config_manager.rb +36 -0
  24. data/lib/woolen_common/drb_helper.rb +125 -0
  25. data/lib/woolen_common/ffi/win32_kernel32.rb +86 -0
  26. data/lib/woolen_common/logger.rb +419 -0
  27. data/lib/woolen_common/pcap/mu/fixnum_ext.rb +8 -0
  28. data/lib/woolen_common/pcap/mu/pcap/ethernet.rb +164 -0
  29. data/lib/woolen_common/pcap/mu/pcap/header.rb +76 -0
  30. data/lib/woolen_common/pcap/mu/pcap/io_pair.rb +68 -0
  31. data/lib/woolen_common/pcap/mu/pcap/io_wrapper.rb +77 -0
  32. data/lib/woolen_common/pcap/mu/pcap/ip.rb +62 -0
  33. data/lib/woolen_common/pcap/mu/pcap/ipv4.rb +274 -0
  34. data/lib/woolen_common/pcap/mu/pcap/ipv6.rb +149 -0
  35. data/lib/woolen_common/pcap/mu/pcap/packet.rb +106 -0
  36. data/lib/woolen_common/pcap/mu/pcap/pkthdr.rb +162 -0
  37. data/lib/woolen_common/pcap/mu/pcap/reader.rb +62 -0
  38. data/lib/woolen_common/pcap/mu/pcap/reader/http_family.rb +175 -0
  39. data/lib/woolen_common/pcap/mu/pcap/sctp.rb +369 -0
  40. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk.rb +124 -0
  41. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/data.rb +135 -0
  42. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/init.rb +101 -0
  43. data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/init_ack.rb +69 -0
  44. data/lib/woolen_common/pcap/mu/pcap/sctp/parameter.rb +111 -0
  45. data/lib/woolen_common/pcap/mu/pcap/sctp/parameter/ip_address.rb +49 -0
  46. data/lib/woolen_common/pcap/mu/pcap/stream_packetizer.rb +74 -0
  47. data/lib/woolen_common/pcap/mu/pcap/tcp.rb +522 -0
  48. data/lib/woolen_common/pcap/mu/pcap/udp.rb +81 -0
  49. data/lib/woolen_common/pcap/mu/scenario/pcap.rb +175 -0
  50. data/lib/woolen_common/pcap/mu/scenario/pcap/fields.rb +51 -0
  51. data/lib/woolen_common/pcap/mu/scenario/pcap/rtp.rb +72 -0
  52. data/lib/woolen_common/pcap/pcap.rb +115 -0
  53. data/lib/woolen_common/pcap/readme.md +72 -0
  54. data/lib/woolen_common/ruby_ext/blank.rb +126 -0
  55. data/lib/woolen_common/ruby_ext/drb_ext.rb +7 -0
  56. data/lib/woolen_common/ruby_ext/string.rb +116 -0
  57. data/lib/woolen_common/ruby_ext/win32_ole.rb +4 -0
  58. data/lib/woolen_common/ruby_proxy.rb +5 -0
  59. data/lib/woolen_common/ruby_proxy/client.rb +305 -0
  60. data/lib/woolen_common/ruby_proxy/config.rb +44 -0
  61. data/lib/woolen_common/ruby_proxy/exceptions.rb +17 -0
  62. data/lib/woolen_common/ruby_proxy/proxy.rb +157 -0
  63. data/lib/woolen_common/ruby_proxy/proxy_global_set.rb +44 -0
  64. data/lib/woolen_common/ruby_proxy/proxy_load.rb +34 -0
  65. data/lib/woolen_common/ruby_proxy/server.rb +53 -0
  66. data/lib/woolen_common/splib.rb +36 -0
  67. data/lib/woolen_common/splib/Array.rb +33 -0
  68. data/lib/woolen_common/splib/CodeReloader.rb +59 -0
  69. data/lib/woolen_common/splib/Constants.rb +44 -0
  70. data/lib/woolen_common/splib/Conversions.rb +47 -0
  71. data/lib/woolen_common/splib/Exec.rb +132 -0
  72. data/lib/woolen_common/splib/Float.rb +13 -0
  73. data/lib/woolen_common/splib/HumanIdealRandomIterator.rb +40 -0
  74. data/lib/woolen_common/splib/Monitor.rb +214 -0
  75. data/lib/woolen_common/splib/PriorityQueue.rb +110 -0
  76. data/lib/woolen_common/splib/Sleep.rb +10 -0
  77. data/lib/woolen_common/splib/UrlShorteners.rb +48 -0
  78. data/lib/woolen_common/ssh_proxy.rb +146 -0
  79. data/lib/woolen_common/system_helper.rb +123 -0
  80. data/lib/woolen_common/system_monitor.rb +23 -0
  81. data/lib/woolen_common/system_monitor/linux_monitor.rb +250 -0
  82. data/lib/woolen_common/system_monitor/windows_monitor.rb +145 -0
  83. data/lib/woolen_common/type_helper.rb +42 -0
  84. data/lib/woolen_common/ver_ctrl_middle_ware.rb +92 -0
  85. data/lib/woolen_common/version.rb +3 -0
  86. metadata +210 -0
@@ -0,0 +1,41 @@
1
+ require 'thread'
2
+
3
+ module ActionPool
4
+ # Adds a little bit extra functionality to the Queue class
5
+ class Queue < ::Queue
6
+ # Create a new Queue for the ActionPool::Pool
7
+ def initialize
8
+ super
9
+ @wait = false
10
+ @pause_guard = Splib::Monitor.new
11
+ @empty_guard = Splib::Monitor.new
12
+ end
13
+ # Stop the queue from returning results to requesting
14
+ # threads. Threads will wait for results until signalled
15
+ def pause
16
+ @wait = true
17
+ end
18
+ # Allow the queue to return results. Any threads waiting
19
+ # will have results given to them.
20
+ def unpause
21
+ @wait = false
22
+ @pause_guard.broadcast
23
+ end
24
+ # Check if queue needs to wait before returning
25
+ def pop
26
+ @pause_guard.wait_while{ @wait }
27
+ o = super
28
+ @empty_guard.broadcast if empty?
29
+ return o
30
+ end
31
+ # Clear queue
32
+ def clear
33
+ super
34
+ @empty_guard.broadcast
35
+ end
36
+ # Park a thread here until queue is empty
37
+ def wait_empty
38
+ @empty_guard.wait_while{ size > 0 }
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,181 @@
1
+ require 'timeout'
2
+
3
+ module ActionPool
4
+ # Exception class used for waking up a thread
5
+ class Wakeup < StandardError
6
+ end
7
+ # Raised within a thread when the timeout is changed
8
+ class Retimeout < StandardError
9
+ end
10
+ class Thread
11
+ # :pool:: pool thread is associated with
12
+ # :t_timeout:: max time a thread is allowed to wait for action
13
+ # :a_timeout:: max time thread is allowed to work
14
+ # :respond_thread:: thread to send execptions to
15
+ # :logger:: LogHelper for logging messages
16
+ # :autostart:: Automatically start the thread
17
+ # Create a new thread
18
+ def initialize(args)
19
+ raise ArgumentError.new('Hash required for initialization') unless args.is_a?(Hash)
20
+ raise ArgumentError.new('ActionPool::Thread requires a pool') unless args[:pool]
21
+ raise ArgumentError.new('ActionPool::Thread requries thread to respond') unless args[:respond_thread]
22
+ @pool = args[:pool]
23
+ @respond_to = args[:respond_thread]
24
+ @thread_timeout = args[:t_timeout] ? args[:t_timeout].to_f : 0
25
+ @action_timeout = args[:a_timeout] ? args[:a_timeout].to_f : 0
26
+ args[:autostart] = true unless args.has_key?(:autostart)
27
+ @kill = false
28
+ @logger = args[:logger].is_a?(Logger) ? args[:logger] : Logger.new(nil)
29
+ @lock = Splib::Monitor.new
30
+ @action = nil
31
+ @thread = args[:autostart] ? ::Thread.new{ start_thread } : nil
32
+ end
33
+
34
+ def start
35
+ @thread = ::Thread.new{ start_thread } if @thread.nil?
36
+ end
37
+
38
+ # :force:: force the thread to stop
39
+ # :wait:: wait for the thread to stop
40
+ # Stop the thread
41
+ def stop(*args)
42
+ @kill = true
43
+ if(args.include?(:force) || waiting?)
44
+ begin
45
+ @thread.raise Wakeup.new
46
+ rescue Wakeup
47
+ #ignore since we are the caller
48
+ end
49
+ sleep(0.01)
50
+ @thread.kill if @thread.alive?
51
+ end
52
+ nil
53
+ end
54
+
55
+ # Currently waiting
56
+ def waiting?
57
+ @action.nil?
58
+ # @status == :wait
59
+ end
60
+
61
+ # Currently running
62
+ def running?
63
+ !@action.nil?
64
+ # @status == :run
65
+ end
66
+
67
+ # Is the thread still alive
68
+ def alive?
69
+ @thread.alive?
70
+ end
71
+
72
+ # Current thread status
73
+ def status
74
+ @action
75
+ end
76
+
77
+ # Join internal thread
78
+ def join
79
+ @thread.join(@action_timeout)
80
+ if(@thread.alive?)
81
+ @thread.kill
82
+ @thread.join
83
+ end
84
+ end
85
+
86
+ # Kill internal thread
87
+ def kill
88
+ @thread.kill
89
+ end
90
+
91
+ # Seconds thread will wait for input
92
+ def thread_timeout
93
+ @thread_timeout
94
+ end
95
+
96
+ # Seconds thread will spend working on a given task
97
+ def action_timeout
98
+ @action_timeout
99
+ end
100
+
101
+ # t:: seconds to wait for input (floats allow for values 0 < t < 1)
102
+ # Set the maximum amount of time to wait for a task
103
+ def thread_timeout=(t)
104
+ t = t.to_f
105
+ raise ArgumentError.new('Value must be great than zero or nil') unless t > 0
106
+ @thread_timeout = t
107
+ @thread.raise Retimeout.new if waiting?
108
+ t
109
+ end
110
+
111
+ # t:: seconds to work on a task (floats allow for values 0 < t < 1)
112
+ # Set the maximum amount of time to work on a given task
113
+ # Note: Modification of this will not affect actions already in process
114
+ def action_timeout=(t)
115
+ t = t.to_f
116
+ raise ArgumentError.new('Value must be great than zero or nil') unless t > 0
117
+ @action_timeout = t
118
+ t
119
+ end
120
+
121
+ private
122
+
123
+ # Start our thread
124
+ def start_thread
125
+ begin
126
+ @logger.info("New pool thread is starting (#{self})")
127
+ until(@kill) do
128
+ begin
129
+ @action = nil
130
+ if(@pool.size > @pool.min && !@thread_timeout.zero?)
131
+ Timeout::timeout(@thread_timeout) do
132
+ @action = @pool.action
133
+ end
134
+ else
135
+ @action = @pool.action
136
+ end
137
+ run(@action[0], @action[1]) unless @action.nil?
138
+ rescue Timeout::Error
139
+ @kill = true
140
+ rescue Wakeup
141
+ @logger.info("Thread #{::Thread.current} was woken up.")
142
+ rescue Retimeout
143
+ @logger.warn('Thread was woken up to reset thread timeout')
144
+ rescue Exception => boom
145
+ @logger.error("Pool thread caught an exception: #{boom}\n#{boom.backtrace.join("\n")}")
146
+ @respond_to.raise boom
147
+ end
148
+ end
149
+ rescue Retimeout
150
+ @logger.warn('Thread was woken up to reset thread timeout')
151
+ retry
152
+ rescue Wakeup
153
+ @logger.info("Thread #{::Thread.current} was woken up.")
154
+ rescue Exception => boom
155
+ @logger.error("Pool thread caught an exception: #{boom}\n#{boom.backtrace.join("\n")}")
156
+ @respond_to.raise boom
157
+ ensure
158
+ @logger.info("Pool thread is shutting down (#{self})")
159
+ @pool.remove(self)
160
+ end
161
+ end
162
+
163
+ # action:: task to be run
164
+ # args:: arguments to be passed to task
165
+ # Run the task
166
+ def run(action, args)
167
+ args = args.respond_to?(:fixed_flatten) ? args.fixed_flatten(1) : args.flatten(1)
168
+ begin
169
+ unless(@action_timeout.zero?)
170
+ Timeout::timeout(@action_timeout) do
171
+ action.call(*args)
172
+ end
173
+ else
174
+ action.call(*args)
175
+ end
176
+ rescue Timeout::Error => boom
177
+ @logger.warn("Pool thread reached max execution time for action: #{boom}")
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,93 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require "#{File.join(File.dirname(__FILE__), 'logger')}"
3
+ require "#{File.join(File.dirname(__FILE__), 'common_helper')}"
4
+ require "#{File.join(File.dirname(__FILE__), 'type_helper')}"
5
+ require 'ipaddr'
6
+ module WoolenCommon
7
+ class AddrHelper
8
+ class << self
9
+ include WoolenCommon::ToolLogger
10
+ # IP地址字符串转做数值(无符号的)
11
+ def ip_str_to_unsigned(ip_addr_str)
12
+ IPAddr.new(ip_addr_str).to_i
13
+ end
14
+
15
+ # IP地址字符串转做数值(有符号的)
16
+ def ip_str_to_signed(ip_addr_str,byte_length=32)
17
+ begin
18
+ return TypeHelper.to_signed(IPAddr.new(ip_addr_str).to_i, byte_length)
19
+ rescue Exception=>e
20
+ debug "对IP地址[#{ip_addr_str}],进行转换到有符号数字出错::#{e.message}"
21
+ return 0
22
+ end
23
+ end
24
+
25
+ # 有符号地址值转成ip字符串
26
+ def signed_to_ip_str(signed,byte_length=32)
27
+ unsigned_32 = TypeHelper.to_unsigned(signed,byte_length)
28
+ IPAddr.new(unsigned_32,Socket::AF_INET).to_s
29
+ end
30
+
31
+ # 无符号地址值转成ip字符串
32
+ def unsigned_to_ip_str(unsigned_32)
33
+ IPAddr.new(unsigned_32,Socket::AF_INET).to_s
34
+ end
35
+
36
+ # mac地址字符串转成无符号数字数组
37
+ def mac_str_to_array(mac_str)
38
+ if mac_str.kind_of? String
39
+ if mac_str.include? ':'
40
+ split_arry = mac_str.split ':'
41
+ elsif mac_str.include? '-'
42
+ split_arry = mac_str.split '-'
43
+ elsif mac_str.length == 12
44
+ split_arry = []
45
+ 6.times do |cnt|
46
+ split_arry << mac_str[(2 * cnt)... (2 * (cnt+1))]
47
+ end
48
+ else
49
+ debug "not support mac format:[#{mac_str}],please use : or - format"
50
+ return []
51
+ end
52
+ if split_arry.length != 6
53
+ debug "to long format:[#{mac_str}]~"
54
+ return []
55
+ end
56
+ return_array=[]
57
+ split_arry.each do |split_str|
58
+ return_array << split_str.to_i(16)
59
+ end
60
+ return_array
61
+ else
62
+ error "not support not string format:[#{mac_str}],please give me a mac string"
63
+ end
64
+ end
65
+
66
+ # mac地址无符号数字数组转字符串
67
+ def array_to_mac_str(mac_array,str_gap=':')
68
+ debug "start to get mac str from mac array :: #{mac_array}"
69
+ if mac_array.kind_of? Array
70
+ if mac_array.length != 6
71
+ error "wrong long arry :[#{mac_array}]~"
72
+ return ''
73
+ else
74
+ ret_str_array = []
75
+ mac_array.each do |mac_int_x16|
76
+ mac_value = TypeHelper.get_low_bit_num(mac_int_x16,8)
77
+ if mac_value >= 16
78
+ ret_str_array << mac_value.to_s(16)
79
+ elsif mac_value >= 0 && mac_int_x16 < 16
80
+ ret_str_array << "0#{mac_value.to_s(16)}"
81
+ end
82
+ end
83
+ debug "success get mac str ::#{ret_str_array.join str_gap}"
84
+ return ret_str_array.join str_gap
85
+ end
86
+ else
87
+ error "not a array mac please give me a array::#{mac_array}~"
88
+ ''
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,305 @@
1
+ # -*- encoding : utf-8 -*-
2
+ #! /usr/bin/env ruby
3
+ #
4
+ # Copyright (C) 2002 Yoshinori K. Okuji <okuji@enbug.org>
5
+ #
6
+ # You may redistribute it and/or modify it under the same term as Ruby.
7
+
8
+ # Cache manager based on the LRU algorithm.
9
+ require "#{File.join(File.dirname(__FILE__), 'logger')}"
10
+ module WoolenCommon
11
+ class Cache
12
+ include ToolLogger
13
+
14
+ CACHE_OBJECT = Struct.new('CacheObject', :content, :size, :atime)
15
+ CACHE_VERSION = '0.3'
16
+
17
+ include Enumerable
18
+
19
+ def self.version
20
+ CACHE_VERSION
21
+ end
22
+
23
+ # initialize(max_obj_size = nil, max_size = nil, max_num = nil,
24
+ # expiration = nil, &hook)
25
+ # initialize(hash, &hook)
26
+ def initialize(*args, &hook)
27
+ if args.size == 1 and args[0].kind_of?(Hash)
28
+ @max_obj_size = @max_size = @max_num = @expiration = nil
29
+ args[0].each do |k, v|
30
+ k = k.intern if k.respond_to?(:intern)
31
+ case k
32
+ when :max_obj_size
33
+ @max_obj_size = v
34
+ when :max_size
35
+ @max_size = v
36
+ when :max_num
37
+ @max_num = v
38
+ when :expiration
39
+ @expiration = v
40
+ else
41
+ warn "cache unknown key :#{k}=>#{v}"
42
+ end
43
+ end
44
+ else
45
+ @max_obj_size, @max_size, @max_num, @expiration = args
46
+ end
47
+
48
+ # Sanity checks.
49
+ if @max_obj_size and @max_size and @max_obj_size > @max_size
50
+ raise ArgumentError, "max_obj_size exceeds max_size (#{@max_obj_size} > #{@max_size})"
51
+ end
52
+ if @max_obj_size and @max_obj_size <= 0
53
+ raise ArgumentError, "invalid max_obj_size `#{@max_obj_size}'"
54
+ end
55
+ if @max_size and @max_size <= 0
56
+ raise ArgumentError, "invalid max_size `#{@max_size}'"
57
+ end
58
+ if @max_num and @max_num <= 0
59
+ raise ArgumentError, "invalid max_num `#{@max_num}'"
60
+ end
61
+ if @expiration and @expiration <= 0
62
+ raise ArgumentError, "invalid expiration `#{@expiration}'"
63
+ end
64
+
65
+ @hook = hook
66
+
67
+ @objs = {}
68
+ @size = 0
69
+ @list = []
70
+
71
+ @hits = 0
72
+ @misses = 0
73
+ end
74
+
75
+ attr_reader :max_obj_size, :max_size, :max_num, :expiration
76
+
77
+ def cached?(key)
78
+ @objs.include?(key)
79
+ end
80
+
81
+ alias :include? :cached?
82
+ alias :member? :cached?
83
+ alias :key? :cached?
84
+ alias :has_key? :cached?
85
+
86
+ def cached_value?(val)
87
+ self.each_value do |v|
88
+ return true if v == val
89
+ end
90
+ false
91
+ end
92
+
93
+ alias :has_value? :cached_value?
94
+ alias :value? :cached_value?
95
+
96
+ def index(val)
97
+ self.each_pair do |k, v|
98
+ return k if v == val
99
+ end
100
+ nil
101
+ end
102
+
103
+ def keys
104
+ @objs.keys
105
+ end
106
+
107
+ def length
108
+ @objs.length
109
+ end
110
+
111
+ alias :size :length
112
+
113
+ def to_hash
114
+ @objs.dup
115
+ end
116
+
117
+ def values
118
+ @objs.collect { |key, obj| obj.content }
119
+ end
120
+
121
+ def invalidate(key)
122
+ obj = @objs[key]
123
+ if obj
124
+ if @hook
125
+ @hook.call(key, obj.content)
126
+ end
127
+ @size -= obj.size
128
+ @objs.delete(key)
129
+ @list.each_index do |i|
130
+ if @list[i] == key
131
+ @list.delete_at(i)
132
+ break
133
+ end
134
+ end
135
+ elsif block_given?
136
+ return yield(key)
137
+ end
138
+ obj.content
139
+ end
140
+
141
+ alias :delete :invalidate
142
+
143
+ def invalidate_all
144
+ if @hook
145
+ @objs.each do |key, obj|
146
+ @hook.call(key, obj)
147
+ end
148
+ end
149
+
150
+ @objs.clear
151
+ @list.clear
152
+ @size = 0
153
+ end
154
+
155
+ alias :clear :invalidate_all
156
+
157
+ def expire
158
+ if @expiration
159
+ now = Time.now.to_i
160
+ @list.each_index do |i|
161
+ key = @list[i]
162
+
163
+ break unless @objs[key].atime + @expiration <= now
164
+ self.invalidate(key)
165
+ end
166
+ end
167
+ # GC.start
168
+ end
169
+
170
+ def [](key)
171
+ self.expire
172
+
173
+ unless @objs.include?(key)
174
+ @misses += 1
175
+ return nil
176
+ end
177
+
178
+ obj = @objs[key]
179
+ obj.atime = Time.now.to_i
180
+
181
+ @list.each_index do |i|
182
+ if @list[i] == key
183
+ @list.delete_at(i)
184
+ break
185
+ end
186
+ end
187
+ @list.push(key)
188
+
189
+ @hits += 1
190
+ obj.content
191
+ end
192
+
193
+ def []=(key, obj)
194
+ self.expire
195
+
196
+ if self.cached?(key)
197
+ self.invalidate(key)
198
+ end
199
+
200
+ size = obj.to_s.size
201
+ if @max_obj_size and @max_obj_size < size
202
+ debug("warning: `#{obj.inspect}' isn't cached because its size exceeds #{@max_obj_size}")
203
+ return obj
204
+ end
205
+ if @max_obj_size.nil? and @max_size and @max_size < size
206
+ debug("warning: `#{obj.inspect}' isn't cached because its size exceeds #{@max_size}")
207
+ return obj
208
+ end
209
+
210
+ if @max_num and @max_num == @list.size
211
+ self.invalidate(@list.first)
212
+ end
213
+
214
+ @size += size
215
+ if @max_size
216
+ while @max_size < @size
217
+ self.invalidate(@list.first)
218
+ end
219
+ end
220
+
221
+ @objs[key] = CACHE_OBJECT.new(obj, size, Time.now.to_i)
222
+ @list.push(key)
223
+
224
+ obj
225
+ end
226
+
227
+ def store(key, value)
228
+ self[key] = value
229
+ end
230
+
231
+ def each_pair
232
+ @objs.each do |key, obj|
233
+ yield key, obj.content
234
+ end
235
+ self
236
+ end
237
+
238
+ alias :each :each_pair
239
+
240
+ def each_key
241
+ @objs.each_key do |key|
242
+ yield key
243
+ end
244
+ self
245
+ end
246
+
247
+ def each_value
248
+ @objs.each_value do |obj|
249
+ yield obj.content
250
+ end
251
+ self
252
+ end
253
+
254
+ def empty?
255
+ @objs.empty?
256
+ end
257
+
258
+ def fetch(key, default = nil)
259
+ val = self[key]
260
+ if val.nil?
261
+ if default
262
+ val = self[key] = default
263
+ elsif block_given?
264
+ val = self[key] = yield(key)
265
+ else
266
+ raise IndexError, "invalid key `#{key}'"
267
+ end
268
+ end
269
+ val
270
+ end
271
+
272
+ # The total size of cached objects, the number of cached objects,
273
+ # the number of cache hits, and the number of cache misses.
274
+ def state_statics
275
+ [@size, @list.size, @hits, @misses]
276
+ end
277
+ end
278
+
279
+ # Run a test, if executed.
280
+ if __FILE__ == $0
281
+ cache = Cache.new(100 * 1024, 100 * 1024 * 1024, 256, 13)
282
+ 1000.times do
283
+ key = rand(1000)
284
+ cache[key] = key.to_s
285
+ end
286
+ 1000.times do
287
+ key = rand(1000)
288
+ puts cache[key]
289
+ end
290
+ sleep 1
291
+ 1000.times do
292
+ key = rand(1000)
293
+ puts cache[key]
294
+ end
295
+
296
+ stat = cache.state_statics
297
+ hits = stat[2]
298
+ misses = stat[3]
299
+ ratio = hits.to_f / (hits + misses)
300
+
301
+ puts "Total size:\t#{stat[0]}"
302
+ puts "Number:\t\t#{stat[1]}"
303
+ puts "Hit ratio:\t#{ratio * 100}% (#{hits} / #{hits + misses})"
304
+ end
305
+ end