Include MonitorMixin in store classes and make them thread-safe.

This commit is contained in:
Akinori MUSHA 2013-03-28 01:05:22 +09:00
parent 30e2915c1e
commit add4a367fd
3 changed files with 79 additions and 58 deletions

View file

@ -1,4 +1,8 @@
require 'monitor'
class HTTP::CookieJar::AbstractStore class HTTP::CookieJar::AbstractStore
include MonitorMixin
class << self class << self
@@class_map = {} @@class_map = {}
@ -31,6 +35,7 @@ class HTTP::CookieJar::AbstractStore
private :default_options private :default_options
def initialize(options = nil) def initialize(options = nil)
super() # MonitorMixin
options ||= {} options ||= {}
@logger = options[:logger] @logger = options[:logger]
# Initializes each instance variable of the same name as option # Initializes each instance variable of the same name as option
@ -65,7 +70,13 @@ class HTTP::CookieJar::AbstractStore
# If (and only if) the +uri+ option is given, last access time of # If (and only if) the +uri+ option is given, last access time of
# each cookie is updated to the current time. # each cookie is updated to the current time.
def each(uri = nil, &block) def each(uri = nil, &block)
raise if uri
raise
else
synchronize {
raise
}
end
self self
end end
include Enumerable include Enumerable

View file

@ -81,15 +81,17 @@ class HTTP::CookieJar
} }
} }
else else
@jar.each { |domain, paths| synchronize {
paths.each { |path, hash| @jar.each { |domain, paths|
hash.delete_if { |name, cookie| paths.each { |path, hash|
if cookie.expired?(now) hash.delete_if { |name, cookie|
true if cookie.expired?(now)
else true
yield cookie else
false yield cookie
end false
end
}
} }
} }
} }
@ -109,45 +111,51 @@ class HTTP::CookieJar
def cleanup(session = false) def cleanup(session = false)
now = Time.now now = Time.now
all_cookies = [] all_cookies = []
@jar.each { |domain, paths|
domain_cookies = []
paths.each { |path, hash| synchronize {
hash.delete_if { |name, cookie| break if @gc_index == 0
if cookie.expired?(now) || (session && cookie.session?)
true @jar.each { |domain, paths|
else domain_cookies = []
domain_cookies << cookie
false paths.each { |path, hash|
end hash.delete_if { |name, cookie|
if cookie.expired?(now) || (session && cookie.session?)
true
else
domain_cookies << cookie
false
end
}
} }
if (debt = domain_cookies.size - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN) > 0
domain_cookies.sort_by!(&:created_at)
domain_cookies.slice!(0, debt).each { |cookie|
delete(cookie)
}
end
all_cookies.concat(domain_cookies)
} }
if (debt = domain_cookies.size - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN) > 0 if (debt = all_cookies.size - HTTP::Cookie::MAX_COOKIES_TOTAL) > 0
domain_cookies.sort_by!(&:created_at) all_cookies.sort_by!(&:created_at)
domain_cookies.slice!(0, debt).each { |cookie| all_cookies.slice!(0, debt).each { |cookie|
delete(cookie) delete(cookie)
} }
end end
all_cookies.concat(domain_cookies) @jar.delete_if { |domain, paths|
} paths.delete_if { |path, hash|
hash.empty?
if (debt = all_cookies.size - HTTP::Cookie::MAX_COOKIES_TOTAL) > 0 }
all_cookies.sort_by!(&:created_at) paths.empty?
all_cookies.slice!(0, debt).each { |cookie|
delete(cookie)
} }
end
@jar.delete_if { |domain, paths| @gc_index = 0
paths.delete_if { |path, hash|
hash.empty?
}
paths.empty?
} }
self
@gc_index = 0
end end
end end
end end

View file

@ -335,9 +335,6 @@ class HTTP::CookieJar
end end
def cleanup(session = false) def cleanup(session = false)
now = Time.now
all_cookies = []
@st_delete_expired ||= @st_delete_expired ||=
@db.prepare("DELETE FROM moz_cookies WHERE expiry < :expiry") @db.prepare("DELETE FROM moz_cookies WHERE expiry < :expiry")
@ -364,26 +361,31 @@ class HTTP::CookieJar
) )
SQL SQL
@st_delete_expired.execute({ 'expiry' => now.to_i }) synchronize {
break if @gc_index == 0
@st_overusing_domains.execute({ @st_delete_expired.execute({ 'expiry' => Time.now.to_i })
'count' => HTTP::Cookie::MAX_COOKIES_PER_DOMAIN
}).each { |row|
domain, count = row['domain'], row['count']
@st_delete_per_domain_overuse.execute({ @st_overusing_domains.execute({
'domain' => domain, 'count' => HTTP::Cookie::MAX_COOKIES_PER_DOMAIN
'limit' => count - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN, }).each { |row|
}) domain, count = row['domain'], row['count']
@st_delete_per_domain_overuse.execute({
'domain' => domain,
'limit' => count - HTTP::Cookie::MAX_COOKIES_PER_DOMAIN,
})
}
overrun = count - HTTP::Cookie::MAX_COOKIES_TOTAL
if overrun > 0
@st_delete_total_overuse.execute({ 'limit' => overrun })
end
@gc_index = 0
} }
self
overrun = count - HTTP::Cookie::MAX_COOKIES_TOTAL
if overrun > 0
@st_delete_total_overuse.execute({ 'limit' => overrun })
end
@gc_index = 0
end end
end end
end end