mirror of
https://github.com/discourse/discourse.git
synced 2025-02-18 13:02:48 +08:00
FIX: emoji cache could get corrupt
FEATURE: enforce 1 day expiry by default on discourse cache remove family expiry concept as the implementation was fragile
This commit is contained in:
parent
8da38cda81
commit
103d42a9d9
|
@ -20,15 +20,15 @@ class Emoji
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.all
|
def self.all
|
||||||
Discourse.cache.fetch("all", family: "emoji") { standard | custom }
|
Discourse.cache.fetch("all_emojis") { standard | custom }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.standard
|
def self.standard
|
||||||
Discourse.cache.fetch("standard", family: "emoji") { load_standard }
|
Discourse.cache.fetch("standard_emojis") { load_standard }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.custom
|
def self.custom
|
||||||
Discourse.cache.fetch("custom", family: "emoji") { load_custom }
|
Discourse.cache.fetch("custom_emojis") { load_custom }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.exists?(name)
|
def self.exists?(name)
|
||||||
|
@ -72,7 +72,9 @@ class Emoji
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.clear_cache
|
def self.clear_cache
|
||||||
Discourse.cache.delete_by_family("emoji")
|
Discourse.cache.delete("custom_emojis")
|
||||||
|
Discourse.cache.delete("standard_emojis")
|
||||||
|
Discourse.cache.delete("all_emojis")
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.db_file
|
def self.db_file
|
||||||
|
|
45
lib/cache.rb
45
lib/cache.rb
|
@ -1,9 +1,15 @@
|
||||||
# Discourse specific cache supports expire by family missing from standard cache
|
# Discourse specific cache, enforces 1 day expiry
|
||||||
|
|
||||||
class Cache < ActiveSupport::Cache::Store
|
class Cache < ActiveSupport::Cache::Store
|
||||||
|
|
||||||
|
# nothing is cached for longer than 1 day EVER
|
||||||
|
# there is no reason to have data older than this clogging redis
|
||||||
|
# it is dangerous cause if we rename keys we will be stuck with
|
||||||
|
# pointless data
|
||||||
|
MAX_CACHE_AGE = 1.day unless defined? MAX_CACHE_AGE
|
||||||
|
|
||||||
def initialize(opts = {})
|
def initialize(opts = {})
|
||||||
opts[:namespace] ||= "_CACHE_"
|
@namespace = opts[:namespace] || "_CACHE_"
|
||||||
super(opts)
|
super(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -11,27 +17,18 @@ class Cache < ActiveSupport::Cache::Store
|
||||||
$redis
|
$redis
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_by_family(key)
|
|
||||||
k = family_key(key, options)
|
|
||||||
redis.smembers(k).each do |member|
|
|
||||||
redis.del(member)
|
|
||||||
end
|
|
||||||
redis.del(k)
|
|
||||||
end
|
|
||||||
|
|
||||||
def reconnect
|
def reconnect
|
||||||
redis.reconnect
|
redis.reconnect
|
||||||
end
|
end
|
||||||
|
|
||||||
def clear
|
def clear
|
||||||
redis.keys.each do |k|
|
redis.keys("#{@namespace}:*").each do |k|
|
||||||
redis.del(k) if k =~ /^_CACHE_:/
|
redis.del(k)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def namespaced_key(key, opts=nil)
|
def namespaced_key(key, opts=nil)
|
||||||
opts ||= options
|
"#{@namespace}:" << key
|
||||||
super(key,opts)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
@ -47,17 +44,8 @@ class Cache < ActiveSupport::Cache::Store
|
||||||
|
|
||||||
def write_entry(key, entry, options)
|
def write_entry(key, entry, options)
|
||||||
dumped = Marshal.dump(entry.value)
|
dumped = Marshal.dump(entry.value)
|
||||||
|
expiry = options[:expires_in] || MAX_CACHE_AGE
|
||||||
if expiry = options[:expires_in]
|
|
||||||
redis.setex(key, expiry, dumped)
|
redis.setex(key, expiry, dumped)
|
||||||
else
|
|
||||||
redis.set(key, dumped)
|
|
||||||
end
|
|
||||||
|
|
||||||
if family = family_key(options[:family], options)
|
|
||||||
redis.sadd(family, key)
|
|
||||||
end
|
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -65,13 +53,4 @@ class Cache < ActiveSupport::Cache::Store
|
||||||
redis.del key
|
redis.del key
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def family_key(name, options)
|
|
||||||
if name
|
|
||||||
key = namespaced_key(name, options)
|
|
||||||
key << "FAMILY:#{name}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,24 +19,15 @@ describe Cache do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can be cleared" do
|
it "can be cleared" do
|
||||||
|
$redis.set("boo", "boo")
|
||||||
cache.write("hello0", "world")
|
cache.write("hello0", "world")
|
||||||
cache.write("hello1", "world")
|
cache.write("hello1", "world")
|
||||||
cache.clear
|
cache.clear
|
||||||
|
|
||||||
|
expect($redis.get("boo")).to eq("boo")
|
||||||
expect(cache.read("hello0")).to eq(nil)
|
expect(cache.read("hello0")).to eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can delete by family" do
|
|
||||||
cache.write("key2", "test", family: "my_family")
|
|
||||||
cache.write("key", "test", expires_in: 1.minute, family: "my_family")
|
|
||||||
|
|
||||||
cache.delete_by_family("my_family")
|
|
||||||
|
|
||||||
expect(cache.fetch("key")).to eq(nil)
|
|
||||||
expect(cache.fetch("key2")).to eq(nil)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it "can delete correctly" do
|
it "can delete correctly" do
|
||||||
cache.fetch("key", expires_in: 1.minute) do
|
cache.fetch("key", expires_in: 1.minute) do
|
||||||
"test"
|
"test"
|
||||||
|
@ -46,16 +37,23 @@ describe Cache do
|
||||||
expect(cache.fetch("key")).to eq(nil)
|
expect(cache.fetch("key")).to eq(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
#TODO yuck on this mock
|
|
||||||
it "calls setex in redis" do
|
it "calls setex in redis" do
|
||||||
cache.delete("key")
|
cache.delete("key")
|
||||||
|
cache.delete("bla")
|
||||||
|
|
||||||
key = cache.namespaced_key("key")
|
key = cache.namespaced_key("key")
|
||||||
$redis.expects(:setex).with(key, 60 , Marshal.dump("bob"))
|
|
||||||
|
|
||||||
cache.fetch("key", expires_in: 1.minute) do
|
cache.fetch("key", expires_in: 1.minute) do
|
||||||
"bob"
|
"bob"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
expect($redis.ttl(key)).to be_within(2.seconds).of(1.minute)
|
||||||
|
|
||||||
|
# we always expire withing a day
|
||||||
|
cache.fetch("bla"){ "hi" }
|
||||||
|
|
||||||
|
key = cache.namespaced_key("bla")
|
||||||
|
expect($redis.ttl(key)).to be_within(2.seconds).of(1.day)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can store and fetch correctly" do
|
it "can store and fetch correctly" do
|
||||||
|
|
Loading…
Reference in New Issue
Block a user