Implement sorted entries cache

sorted_entries cached
This commit is contained in:
Leeingnyo
2021-08-22 23:51:23 +09:00
parent 4a09aee177
commit bf81a4e48b
4 changed files with 107 additions and 0 deletions

View File

@@ -157,3 +157,90 @@ class InfoCache
@@cached_sort_opt_previous = {} of String => Hash(String, SortOptions)
end
end
private class SortedEntriesCacheEntry
getter key : String, atime : Time
def initialize(@ctime : Time, @key : String, @value : Array(String))
@atime = @ctime
end
def value
@atime = Time.utc
@value
end
def instance_size
@value.size * (instance_sizeof(String) + sizeof(String)) +
@value.sum(&.size) + instance_sizeof(SortedEntriesCacheEntry)
end
end
# LRU Cache
class SortedEntriesCache
@@limit : Int128 = Int128.new 1024 * 1024 * 50 # 50MB
# key => entry
@@cache = {} of String => SortedEntriesCacheEntry
def self.gen_key(book_id : String, username : String,
entries : Array(Entry), opt : SortOptions?)
sig = Digest::SHA1.hexdigest (entries.map &.id).to_s
user_context = opt && opt.method == SortMethod::Progress ? username : ""
Digest::SHA1.hexdigest (book_id + sig + user_context +
(opt ? opt.to_tuple.to_s : "nil"))
end
def self.get(key : String)
entry = @@cache[key]?
Logger.debug "SortedEntries Cache Hit! #{key}" unless entry.nil?
Logger.debug "SortedEntries Cache Miss #{key}" if entry.nil?
return ids2entries entry.value unless entry.nil?
end
def self.set(key : String, value : Array(Entry))
@@cache[key] = SortedEntriesCacheEntry.new Time.utc, key, value.map &.id
Logger.debug "SortedEntries Cached #{key}"
remove_victim_cache
end
def self.invalidate(key : String)
@@cache.delete key
end
def self.print
sum = @@cache.sum { |_, entry| entry.instance_size }
Logger.debug "---- Sorted Entries Cache ----"
Logger.debug "Size: #{sum} Bytes"
Logger.debug "List:"
@@cache.each { |k, v| Logger.debug "#{k} | #{v.atime}" }
Logger.debug "------------------------------"
end
private def self.ids2entries(ids : Array(String))
e_map = Library.default.deep_entries.to_h { |entry| {entry.id, entry} }
entries = [] of Entry
begin
ids.each do |id|
entries << e_map[id]
end
return entries if ids.size == entries.size
rescue
end
end
private def self.is_cache_full
sum = @@cache.sum { |_, entry| entry.instance_size }
sum > @@limit
end
private def self.remove_victim_cache
while is_cache_full && @@cache.size > 0
Logger.debug "SortedEntries Cache Full! Remove LRU"
min = @@cache.min_by? { |_, entry| entry.atime }
Logger.debug "Target: #{min[0]}, Last Access Time: #{min[1].atime}" if min
invalidate min[0] if min
print if Logger.get_severity == Log::Severity::Debug
end
end
end