swiftiply 0.6.1.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.
- checksums.yaml +7 -0
- data/CONTRIBUTORS +2 -0
- data/README.md +62 -0
- data/bin/{mongrel_rails → evented_mongrel_rails} +6 -14
- data/bin/swiftiplied_mongrel_rails +246 -0
- data/bin/swiftiply +136 -116
- data/bin/swiftiply_mongrel_rails +2 -2
- data/bin/swiftiplyctl +283 -0
- data/cleanup.sh +5 -0
- data/ext/deque/extconf.rb +162 -0
- data/ext/deque/swiftcore/rubymain.cpp +435 -0
- data/ext/fastfilereader/extconf.rb +2 -2
- data/ext/fastfilereader/mapper.cpp +2 -0
- data/ext/map/extconf.rb +161 -0
- data/ext/map/rubymain.cpp +500 -0
- data/ext/splaytree/extconf.rb +161 -0
- data/ext/splaytree/swiftcore/rubymain.cpp +580 -0
- data/ext/splaytree/swiftcore/splay_map.h +635 -0
- data/ext/splaytree/swiftcore/splay_set.h +575 -0
- data/ext/splaytree/swiftcore/splay_tree.h +1127 -0
- data/external/httpclient.rb +231 -0
- data/external/package.rb +13 -13
- data/setup.rb +18 -2
- data/src/swiftcore/Swiftiply.rb +417 -773
- data/src/swiftcore/Swiftiply/backend_protocol.rb +213 -0
- data/src/swiftcore/Swiftiply/cache_base.rb +49 -0
- data/src/swiftcore/Swiftiply/cache_base_mixin.rb +52 -0
- data/src/swiftcore/Swiftiply/cluster_managers/rest_based_cluster_manager.rb +9 -0
- data/src/swiftcore/Swiftiply/cluster_protocol.rb +70 -0
- data/src/swiftcore/Swiftiply/config.rb +370 -0
- data/src/swiftcore/Swiftiply/config/rest_updater.rb +26 -0
- data/src/swiftcore/Swiftiply/constants.rb +101 -0
- data/src/swiftcore/Swiftiply/content_cache_entry.rb +44 -0
- data/src/swiftcore/Swiftiply/content_response.rb +45 -0
- data/src/swiftcore/Swiftiply/control_protocol.rb +49 -0
- data/src/swiftcore/Swiftiply/dynamic_request_cache.rb +41 -0
- data/src/swiftcore/Swiftiply/etag_cache.rb +64 -0
- data/src/swiftcore/Swiftiply/file_cache.rb +46 -0
- data/src/swiftcore/Swiftiply/hash_cache_base.rb +22 -0
- data/src/swiftcore/Swiftiply/http_recognizer.rb +267 -0
- data/src/swiftcore/Swiftiply/loggers/Analogger.rb +21 -0
- data/src/swiftcore/Swiftiply/loggers/stderror.rb +13 -0
- data/src/swiftcore/Swiftiply/mocklog.rb +10 -0
- data/src/swiftcore/Swiftiply/proxy.rb +15 -0
- data/src/swiftcore/Swiftiply/proxy_backends/keepalive.rb +286 -0
- data/src/swiftcore/Swiftiply/proxy_backends/traditional.rb +286 -0
- data/src/swiftcore/Swiftiply/proxy_backends/traditional/redis_directory.rb +87 -0
- data/src/swiftcore/Swiftiply/proxy_backends/traditional/static_directory.rb +69 -0
- data/src/swiftcore/Swiftiply/proxy_bag.rb +716 -0
- data/src/swiftcore/Swiftiply/rest_based_cluster_manager.rb +15 -0
- data/src/swiftcore/Swiftiply/splay_cache_base.rb +21 -0
- data/src/swiftcore/Swiftiply/support_pagecache.rb +6 -3
- data/src/swiftcore/Swiftiply/swiftiply_2_http_proxy.rb +7 -0
- data/src/swiftcore/Swiftiply/swiftiply_client.rb +20 -5
- data/src/swiftcore/Swiftiply/version.rb +5 -0
- data/src/swiftcore/evented_mongrel.rb +26 -8
- data/src/swiftcore/hash.rb +43 -0
- data/src/swiftcore/method_builder.rb +28 -0
- data/src/swiftcore/streamer.rb +46 -0
- data/src/swiftcore/swiftiplied_mongrel.rb +91 -23
- data/src/swiftcore/types.rb +20 -3
- data/swiftiply.gemspec +14 -8
- data/test/TC_Deque.rb +152 -0
- data/test/TC_ProxyBag.rb +147 -166
- data/test/TC_Swiftiply.rb +576 -169
- data/test/TC_Swiftiply/mongrel/evented_hello.rb +1 -1
- data/test/TC_Swiftiply/mongrel/swiftiplied_hello.rb +1 -1
- data/test/TC_Swiftiply/test_serve_static_file_xsendfile/sendfile_client.rb +27 -0
- data/test/TC_Swiftiply/test_ssl/bin/validate_ssl_capability.rb +21 -0
- data/test/TC_Swiftiply/test_ssl/test.cert +16 -0
- data/test/TC_Swiftiply/test_ssl/test.key +15 -0
- data/{bin → test/bin}/echo_client +0 -0
- metadata +136 -94
- data/README +0 -126
- data/ext/swiftiply_parse/parse.rl +0 -90
@@ -0,0 +1,26 @@
|
|
1
|
+
# Encoding:ascii-8bit
|
2
|
+
|
3
|
+
module Swiftcore
|
4
|
+
module Swiftiply
|
5
|
+
class Config
|
6
|
+
class RestUpdater
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def start
|
13
|
+
host = @config[Chost] || '127.0.0.1'
|
14
|
+
port = @config[Cport] || 9949
|
15
|
+
end
|
16
|
+
|
17
|
+
class RestUpdaterProtocol < EventMachine::Connection
|
18
|
+
def receive_data data
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module Swiftcore
|
2
|
+
|
3
|
+
Deque = Array unless HasDeque or const_defined?(:Deque)
|
4
|
+
|
5
|
+
module Swiftiply
|
6
|
+
|
7
|
+
# Yeah, these constants look kind of tacky. Inside of tight loops,
|
8
|
+
# though, using them makes a small but measurable difference, and those
|
9
|
+
# small differences add up....
|
10
|
+
C_asterisk = '*'.freeze
|
11
|
+
C_colon = ':'.freeze
|
12
|
+
C_empty = ''.freeze
|
13
|
+
C_header_close = 'HTTP/1.1 200 OK\r\nConnection: close\r\n'.freeze
|
14
|
+
C_header_keepalive = 'HTTP/1.1 200 OK\r\n'.freeze
|
15
|
+
C_localhost = '127.0.0.1'.freeze
|
16
|
+
C_minus = '-'.freeze
|
17
|
+
C_plus = '+'.freeze
|
18
|
+
C_slash = '/'.freeze
|
19
|
+
C_slashindex_html = '/index.html'.freeze
|
20
|
+
C1_0 = '1.0'.freeze
|
21
|
+
C1_1 = '1.1'.freeze
|
22
|
+
C_304 = "HTTP/1.1 304 Not Modified\r\n".freeze
|
23
|
+
C_date_header_range = 6..-5
|
24
|
+
C80 = '80'.freeze
|
25
|
+
Caos = 'application/octet-stream'.freeze
|
26
|
+
Cat = 'at'.freeze
|
27
|
+
Ccache_directory = 'cache_directory'.freeze
|
28
|
+
Ccache_extensions = 'cache_extensions'.freeze
|
29
|
+
Ccallsite = 'callsite'.freeze
|
30
|
+
Cclassname = 'classname'.freeze
|
31
|
+
Ccluster_address = 'cluster_address'.freeze
|
32
|
+
Ccluster_port = 'cluster_port'.freeze
|
33
|
+
Ccluster_server = 'cluster_server'.freeze
|
34
|
+
CConnection_close = "Connection: close\r\n".freeze
|
35
|
+
CConnection_KeepAlive = "Connection: Keep-Alive\r\n".freeze
|
36
|
+
CBackendAddress = 'BackendAddress'.freeze
|
37
|
+
CBackendPort = 'BackendPort'.freeze
|
38
|
+
Cbackup = 'backup'.freeze
|
39
|
+
Ccertfile = 'certfile'.freeze
|
40
|
+
Cchunked_encoding_threshold = 'chunked_encoding_threshold'.freeze
|
41
|
+
Cxforwardedfor = 'xforwardedfor'.freeze
|
42
|
+
Cdaemonize = 'daemonize'.freeze
|
43
|
+
Cdefault = 'default'.freeze
|
44
|
+
CDELETE = 'DELETE'.freeze
|
45
|
+
Cdescriptor_cache = 'descriptor_cache_threshold'.freeze
|
46
|
+
Cdescriptors = 'descriptors'.freeze
|
47
|
+
Cdirectory = 'directory'.freeze
|
48
|
+
Cdocroot = 'docroot'.freeze
|
49
|
+
Cdynamic_request_cache = 'dynamic_request_cache'.freeze
|
50
|
+
Cenable_sendfile_404 = 'enable_sendfile_404'.freeze
|
51
|
+
Cepoll = 'epoll'.freeze
|
52
|
+
Cepoll_descriptors = 'epoll_descriptors'.freeze
|
53
|
+
Cetag_cache = 'etag_cache'.freeze
|
54
|
+
Cfile_cache = 'file_cache'.freeze
|
55
|
+
CGET = 'GET'.freeze
|
56
|
+
Cgroup = 'group'.freeze
|
57
|
+
CHEAD = 'HEAD'.freeze
|
58
|
+
Chost = 'host'.freeze
|
59
|
+
Cincoming = 'incoming'.freeze
|
60
|
+
Cinfo = 'info'.freeze
|
61
|
+
Ckeepalive = 'keepalive'.freeze
|
62
|
+
Ckey = 'key'.freeze
|
63
|
+
Ckeyfile = 'keyfile'.freeze
|
64
|
+
Cmanager = 'manager'.freeze
|
65
|
+
Cmap = 'map'.freeze
|
66
|
+
Cmax_cache_size = 'max_cache_size'.freeze
|
67
|
+
Cmsg_expired = 'browser connection expired'.freeze
|
68
|
+
Coutgoing = 'outgoing'.freeze
|
69
|
+
Cparams = 'params'.freeze
|
70
|
+
Cport = 'port'.freeze
|
71
|
+
CPOST = 'POST'.freeze
|
72
|
+
Cproxy = 'proxy'.freeze
|
73
|
+
CPUT = 'PUT'.freeze
|
74
|
+
Credeployable = 'redeployable'.freeze
|
75
|
+
Credeployment_sizelimit = 'redeployment_sizelimit'.freeze
|
76
|
+
Crequire = 'require'.freeze
|
77
|
+
Csendfileroot = 'sendfileroot'.freeze
|
78
|
+
Cservers = 'servers'.freeze
|
79
|
+
Cssl = 'ssl'.freeze
|
80
|
+
Csize = 'size'.freeze
|
81
|
+
Cstaticmask = 'staticmask'.freeze
|
82
|
+
Cswiftclient = 'swiftclient'.freeze
|
83
|
+
Cthreshold = 'threshold'.freeze
|
84
|
+
Ctimeslice = 'timeslice'.freeze
|
85
|
+
Ctimeout = 'timeout'.freeze
|
86
|
+
Cupdates = 'updates'.freeze
|
87
|
+
Curl = 'url'.freeze
|
88
|
+
Cuser = 'user'.freeze
|
89
|
+
Cwindow = 'window'.freeze
|
90
|
+
|
91
|
+
C_fsep = File::SEPARATOR
|
92
|
+
|
93
|
+
UnknownSocket = Socket::pack_sockaddr_in(0,'0.0.0.0')
|
94
|
+
|
95
|
+
RunningConfig = {}
|
96
|
+
|
97
|
+
class EMStartServerError < RuntimeError; end
|
98
|
+
class SwiftiplyLoggerNotFound < RuntimeError; end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# This was inspired by Paul Sadauskas' Resourceful library: http://github.com/paul/resourceful
|
2
|
+
module Swiftcore
|
3
|
+
module Swiftiply
|
4
|
+
class ContentCacheEntry < ::Hash
|
5
|
+
|
6
|
+
# @param [Resourceful::Request] request
|
7
|
+
# The request whose response we are storing in the cache.
|
8
|
+
# @param response<Resourceful::Response>
|
9
|
+
# The Response obhect to be stored.
|
10
|
+
def initialize(request, response)
|
11
|
+
super()
|
12
|
+
self[:request_uri] = request.uri
|
13
|
+
self[:request_time] = request.request_time
|
14
|
+
self[:request_vary_headers] = select_request_headers(request, response)
|
15
|
+
self[:response] = response
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns true if this entry may be used to fullfil the given request,
|
19
|
+
# according to the vary headers.
|
20
|
+
#
|
21
|
+
# @param request<Resourceful::Request>
|
22
|
+
# The request to do the lookup on.
|
23
|
+
def valid_for?(request)
|
24
|
+
request.uri == self[:request_uri] && self[:request_vary_headers].all? {|key, value| request.header[key] == value }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Selects the headers from the request named by the response's Vary header
|
28
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.6
|
29
|
+
#
|
30
|
+
# @param [Resourceful::Request] request
|
31
|
+
# The request used to obtain the response.
|
32
|
+
# @param [Resourceful::Response] response
|
33
|
+
# The response obtained from the request.
|
34
|
+
def select_request_headers(request, response)
|
35
|
+
headers = {}
|
36
|
+
|
37
|
+
# Broken
|
38
|
+
self[:response].header['Vary'].each { |name| header[name] = request.header[name] if request.header[name] } if response.header['Vary']
|
39
|
+
|
40
|
+
header
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Swiftcore
|
4
|
+
module Swiftiply
|
5
|
+
class ContentResponse < ::Hash
|
6
|
+
# data,etag,mtime,path,cookies,headers
|
7
|
+
def initialize(uri, headers, cacheable_data)
|
8
|
+
parse_basic_http_data headers
|
9
|
+
self[:uri] = uri
|
10
|
+
self[:headers] = headers
|
11
|
+
self[:data] = cacheable_data
|
12
|
+
self[:ETag] ||= Digest::MD5.hexdigest(cacheable_data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse_basic_http_data(headers)
|
16
|
+
# The basic interesting pieces are ETag, Date, Expires, Vary, and Cache-Control.
|
17
|
+
# I can hear you thinking right now that a line of 'if' statements is gross.
|
18
|
+
# You're right. It's also a heaping hell of a lot faster than using something
|
19
|
+
# like #scan. So, for this code, you'll just have to accept it.
|
20
|
+
# Thanks for your consideration.
|
21
|
+
if headers =~ /ETag:\s+(.*)/
|
22
|
+
self[:ETag] = $1
|
23
|
+
end
|
24
|
+
if headers =~ /Date:\s+(.*)/
|
25
|
+
self[:Date] = $1
|
26
|
+
end
|
27
|
+
if headers =~ /Expires:\s+(.*)/
|
28
|
+
self[:Expires] = $1
|
29
|
+
end
|
30
|
+
if headers =~ /Vary:\s+(.*)/
|
31
|
+
self[:Vary] = $1
|
32
|
+
end
|
33
|
+
if headers =~ /Cache-Control:\s+(.*)/
|
34
|
+
self[:Cache_Control] = $1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def header(header_name)
|
39
|
+
name_symbol = header_name.to_sym
|
40
|
+
self[name_symbol] || (self[:headers] =~ /#{header_name}:\s+(.*)/ && self[name_symbol] = $1)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "swiftcore/Swiftiply/http_recognizer"
|
2
|
+
|
3
|
+
module Swiftcore
|
4
|
+
module Swiftiply
|
5
|
+
|
6
|
+
# The ControlProtocol implements a simple REST HTTP handler that can be
|
7
|
+
# used to affect the running configuration of Swiftiply.
|
8
|
+
|
9
|
+
class ControlProtocol < HttpRecognizer
|
10
|
+
|
11
|
+
# Should be able to use this to control all aspects of Swuftiply configuration and behavior.
|
12
|
+
# - Query current performance information and statistics
|
13
|
+
# * GET /status
|
14
|
+
# * GET /status/DOMAIN
|
15
|
+
# * GET /domains
|
16
|
+
# * GET /config/DOMAIN
|
17
|
+
# - Supply new config sections (json payload?)
|
18
|
+
# * POST /config/DOMAIN
|
19
|
+
# * PUT /config/DOMAIN
|
20
|
+
# (There is currently no useful differentiation between the use of
|
21
|
+
# POST and PUT in the API; they are both idempotent operations
|
22
|
+
# that place the provided configuration into Swiftiply.)
|
23
|
+
# - Remove config sections
|
24
|
+
# * DELETE /config/DOMAIN
|
25
|
+
def push
|
26
|
+
case @request_method
|
27
|
+
when CGET
|
28
|
+
case @uri
|
29
|
+
when /\/status(\/(.*))$/
|
30
|
+
when /\/domains/
|
31
|
+
when /\/config\/(.+)$/
|
32
|
+
end
|
33
|
+
when CPOST, CPUT
|
34
|
+
case @uri
|
35
|
+
when /\/config\/(.+)$/
|
36
|
+
end
|
37
|
+
when CDELETE
|
38
|
+
case @uri
|
39
|
+
when /\/config\/(.+)$/
|
40
|
+
end
|
41
|
+
else
|
42
|
+
# No supported method; discard
|
43
|
+
close_connection
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
begin
|
2
|
+
load_attempted ||= false
|
3
|
+
require 'swiftcore/Swiftiply/cache_base'
|
4
|
+
rescue LoadError => e
|
5
|
+
if !load_attempted
|
6
|
+
load_attempted = true
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
rescue LoadError
|
10
|
+
raise e
|
11
|
+
end
|
12
|
+
retry
|
13
|
+
end
|
14
|
+
raise e
|
15
|
+
end
|
16
|
+
|
17
|
+
module Swiftcore
|
18
|
+
module Swiftiply
|
19
|
+
class DynamicRequestCache < CacheBase
|
20
|
+
attr_accessor :one_client_name
|
21
|
+
|
22
|
+
def initialize(docroot, vw, ts, maxsize)
|
23
|
+
@docroot = docroot
|
24
|
+
super(vw,ts,maxsize)
|
25
|
+
end
|
26
|
+
|
27
|
+
def verify(path)
|
28
|
+
if @docroot && self[path]
|
29
|
+
if ProxyBag.find_static_file(@docroot,path,@one_client_name)
|
30
|
+
self.delete path
|
31
|
+
false
|
32
|
+
else
|
33
|
+
true
|
34
|
+
end
|
35
|
+
else
|
36
|
+
false
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
begin
|
2
|
+
load_attempted ||= false
|
3
|
+
require 'swiftcore/Swiftiply/cache_base'
|
4
|
+
require 'digest/md5'
|
5
|
+
rescue LoadError => e
|
6
|
+
if !load_attempted
|
7
|
+
load_attempted = true
|
8
|
+
begin
|
9
|
+
require 'rubygems'
|
10
|
+
rescue LoadError
|
11
|
+
raise e
|
12
|
+
end
|
13
|
+
retry
|
14
|
+
end
|
15
|
+
raise e
|
16
|
+
end
|
17
|
+
|
18
|
+
module Swiftcore
|
19
|
+
module Swiftiply
|
20
|
+
|
21
|
+
ReadMode = 'rb'.freeze
|
22
|
+
|
23
|
+
class EtagCache < CacheBase
|
24
|
+
|
25
|
+
def etag_mtime(path)
|
26
|
+
self[path] || self[path] = self.calculate_etag(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def etag(path)
|
30
|
+
self[path] && self[path].first || (self[path] = self.calculate_etag(path)).first
|
31
|
+
end
|
32
|
+
|
33
|
+
def mtime(path)
|
34
|
+
self[path] && self[path].last || (self[path] = self.calculate_etag(path)).last
|
35
|
+
end
|
36
|
+
|
37
|
+
def verify(path)
|
38
|
+
if et = self[path] and File.exist?(path)
|
39
|
+
mt = File.mtime(path)
|
40
|
+
if mt == et.last
|
41
|
+
true
|
42
|
+
else
|
43
|
+
(self[path] = self.calculate_etag(path)).first
|
44
|
+
end
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def calculate_etag(path)
|
51
|
+
digest = Digest::MD5.new
|
52
|
+
buffer = ''
|
53
|
+
# This seems to be the fastest of several different ways to read a file for generating a digest.
|
54
|
+
File.open(path,ReadMode) {|fh| digest << buffer while fh.read(4096,buffer)}
|
55
|
+
etag = digest.hexdigest
|
56
|
+
unless self[path]
|
57
|
+
add_to_verification_queue(path)
|
58
|
+
ProxyBag.log(owner_hash).log('info',"Adding ETag #{etag} for #{path} to ETag cache") if ProxyBag.level(owner_hash) > 2
|
59
|
+
end
|
60
|
+
[etag,File.mtime(path)]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
begin
|
2
|
+
load_attempted ||= false
|
3
|
+
require 'swiftcore/Swiftiply/cache_base'
|
4
|
+
rescue LoadError => e
|
5
|
+
if !load_attempted
|
6
|
+
load_attempted = true
|
7
|
+
begin
|
8
|
+
require 'rubygems'
|
9
|
+
rescue LoadError
|
10
|
+
raise e
|
11
|
+
end
|
12
|
+
retry
|
13
|
+
end
|
14
|
+
raise e
|
15
|
+
end
|
16
|
+
|
17
|
+
module Swiftcore
|
18
|
+
module Swiftiply
|
19
|
+
class FileCache < CacheBase
|
20
|
+
|
21
|
+
def add(path_info,path,data,etag,mtime,cookie,header)
|
22
|
+
unless self[path_info]
|
23
|
+
add_to_verification_queue(path_info)
|
24
|
+
ProxyBag.log(owner_hash).log('info',"Adding file #{path} to file cache as #{path_info}") if ProxyBag.level(owner_hash) > 2
|
25
|
+
end
|
26
|
+
self[path_info] = [data,etag,mtime,path,cookie,header]
|
27
|
+
end
|
28
|
+
|
29
|
+
def verify(path_info)
|
30
|
+
if f = self[path_info]
|
31
|
+
if File.exist?(f[3]) and File.mtime(f[3]) == f[2]
|
32
|
+
true
|
33
|
+
else
|
34
|
+
ProxyBag.log(owner_hash).log('info',"Removing file #{path_info} from file cache") if ProxyBag.level(owner_hash) > 2
|
35
|
+
false
|
36
|
+
end
|
37
|
+
else
|
38
|
+
# It was in the verification queue, but not in the file cache.
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'swiftcore/Swiftiply/cache_base_mixin'
|
2
|
+
|
3
|
+
module Swiftcore
|
4
|
+
# Use Array instead of Deque, if Deque wasn't available.
|
5
|
+
Deque = Array unless HasDeque or const_defined?(:Deque)
|
6
|
+
|
7
|
+
module Swiftiply
|
8
|
+
class CacheBase < Hash
|
9
|
+
include CacheBaseMixin
|
10
|
+
|
11
|
+
def initialize(vw = 900, time_limit = 0.05, maxsize = nil)
|
12
|
+
@vw = vw
|
13
|
+
@tl = time_limit
|
14
|
+
@wvtl = vw * time_limit
|
15
|
+
@old_vql = 0
|
16
|
+
@vq = Deque.new
|
17
|
+
@maxsize = maxsize #max size is irrelevant for a vanilla hash, but it'll be tracked anyway
|
18
|
+
super()
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|