Skip to content

Instantly share code, notes, and snippets.

@hiroara
Last active November 17, 2020 06:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hiroara/5c776b3b5731fc258a3cd879d1b345c4 to your computer and use it in GitHub Desktop.
Save hiroara/5c776b3b5731fc258a3cd879d1b345c4 to your computer and use it in GitHub Desktop.
Analyze Redis data usage
#!/usr/bin/env ruby
require 'csv'
class Level
attr_reader :key, :parent, :bytesize, :total_bytesize, :children
def initialize parent, key, bytesize = 0
@parent = parent
@key = key
@bytesize = bytesize
@total_bytesize = bytesize
@children = {}
end
def eql? other
other.is_a?(Level) && other.key == self.key
end
def hash
self.key.hash * 3 + 13
end
def full_key
self.parent.full_key + ":#{self.key}"
end
def to_str
"<Item##{self.full_key} total_bytesize=#{self.total_bytesize}>"
end
alias to_s to_str
def add child
if self.children.key? child.key
self.children[child.key].bytesize = child.bytesize
return self.children[child.key]
end
self.children[child.key] = child.tap { |ch| add_bytesize ch.total_bytesize }
end
alias << add
def print_tree output, indent: 0, depth: nil, threshold: nil
output.puts "#{self.key || '<root>'}: #{self.total_bytesize}#{" (#{self.bytesize})" if self.bytesize > 0}"
return if !depth.nil? && depth <= 0
options = { indent: indent + 1, depth: depth.nil? ? nil : depth - 1, threshold: threshold }
self.children.values.lazy
.select { |child| threshold.nil? || child.total_bytesize >= threshold }
.each do |child|
output.print "#{' ' * indent}|- "
child.print_tree(output, **options)
end
end
def bytesize= value
diff = value - self.bytesize
@bytesize = value
self.add_bytesize diff
end
protected
def add_bytesize bytesize
@total_bytesize += bytesize
self.parent.add_bytesize bytesize if self.parent
end
end
root = Level.new nil, nil
# ARGF should be a file generated with redis-rdb-tools with `-c memory` option.
# See: https://github.com/sripathikrishnan/redis-rdb-tools/tree/548b11ec3c81a603f5b321228d07a61a0b940159#generate-memory-report
CSV.new(ARGF, headers: true).each_with_index do |row|
cursor = root
tokens = row['key'].split(':')
item_token = tokens.pop
tokens.each { |token| cursor = cursor.add(Level.new(cursor, token)) }
cursor << Level.new(cursor, item_token, row['size_in_bytes'].to_i)
end
root.print_tree STDOUT, threshold: 1024**2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment