class Eternity::Blob

Attributes

sha1[R]
type[R]

Public Class Methods

cache_size() click to toggle source
# File lib/eternity/blob.rb, line 68
def cache_size
  Eternity.connection.call('KEYS', Eternity.keyspace[:blob]['*']).count
end
clear_cache() click to toggle source
# File lib/eternity/blob.rb, line 62
def clear_cache
  Eternity.connection.call('KEYS', Eternity.keyspace[:blob]['*']).each_slice(1000) do |keys|
    Eternity.connection.call 'DEL', *keys
  end
end
deserialize(string) click to toggle source
# File lib/eternity/blob.rb, line 39
def deserialize(string)
  MessagePack.unpack string
end
digest(string) click to toggle source
# File lib/eternity/blob.rb, line 31
def digest(string)
  Digest::SHA1.hexdigest string
end
new(type, sha1) click to toggle source
# File lib/eternity/blob.rb, line 6
def initialize(type, sha1)
  @type = type
  @sha1 = sha1
end
normalize(data) click to toggle source
# File lib/eternity/blob.rb, line 43
def normalize(data)
  if data.kind_of? Hash
    sorted_data = Hash[data.sort_by { |k,v| k.to_s }]
    sorted_data.each { |k,v| sorted_data[k] = normalize v }

  elsif data.kind_of? Array
    data.map { |v| normalize v }

  elsif data.kind_of? String
    data.encode 'UTF-8'

  elsif data.respond_to? :utc
    data.utc.strftime TIME_FORMAT

  else
    data
  end
end
orphan_files() click to toggle source
# File lib/eternity/blob.rb, line 72
def orphan_files
  repositories = Repository.all
  
  repo_commits = repositories.map { |r| r.current_commit } + 
                 repositories.flat_map { |r| r.branches.values.map { |c| Commit.new c } }
  
  branch_commits = Branch.names.map { |b| Branch[b] }

  used_by_type = {
    commit: (repo_commits.flat_map { |c| [c.id] + c.history_ids } + branch_commits.flat_map { |c| [c.id] + c.history_ids }).uniq
  }

  commit_blobs = used_by_type[:commit].map { |id| Blob.read :commit, id }

  [:index, :delta, :history].each do |type|
    used_by_type[type] = commit_blobs.map { |b| b[type.to_s] }.compact
  end

  used_by_type.each_with_object({}) do |(type, used), hash|
    hash[type] = files_of(type) - used.map { |id| file_for type, id }
  end
end
read(type, sha1) click to toggle source
# File lib/eternity/blob.rb, line 27
def read(type, sha1)
  deserialize read_redis(type, sha1) || read_file(type, sha1)
end
serialize(data) click to toggle source
# File lib/eternity/blob.rb, line 35
def serialize(data)
  MessagePack.pack normalize(data)
end
write(type, data) click to toggle source
# File lib/eternity/blob.rb, line 17
def write(type, data)
  serialization = serialize data
  sha1 = digest serialization

  write_redis type, sha1, serialization
  write_file type, sha1, serialization

  sha1
end

Private Class Methods

file_for(type, sha1) click to toggle source
# File lib/eternity/blob.rb, line 126
def file_for(type, sha1)
  File.join Eternity.blob_path, type.to_s, sha1[0..1], sha1[2..-1]
end
files_of(type) click to toggle source
# File lib/eternity/blob.rb, line 130
def files_of(type)
  Dir.glob File.join(Eternity.blob_path, type.to_s, '*', '*')
end
read_file(type, sha1) click to toggle source
# File lib/eternity/blob.rb, line 117
def read_file(type, sha1)
  serialization = Base64.decode64(IO.read(file_for(type, sha1)))
  write_redis type, sha1, serialization
  serialization

rescue Errno::ENOENT
  raise "Blob not found: #{type} -> #{sha1}"
end
read_redis(type, sha1) click to toggle source
# File lib/eternity/blob.rb, line 104
def read_redis(type, sha1)
  Eternity.connection.call 'GET', Eternity.keyspace[:blob][type][sha1]
end
write_file(type, sha1, serialization) click to toggle source
# File lib/eternity/blob.rb, line 108
def write_file(type, sha1, serialization)
  filename = file_for type, sha1
  if !File.exist? filename
    dirname = File.dirname filename
    FileUtils.mkpath dirname unless Dir.exist? dirname
    File.write filename, Base64.encode64(serialization)
  end
end
write_redis(type, sha1, serialization) click to toggle source
# File lib/eternity/blob.rb, line 97
def write_redis(type, sha1, serialization)
  if serialization.size <= Eternity.blob_cache_max_size
    Eternity.connection.call 'SET', Eternity.keyspace[:blob][type][sha1], serialization, 
                             'EX', Eternity.blob_cache_expiration
  end
end

Public Instance Methods

data() click to toggle source
# File lib/eternity/blob.rb, line 11
def data
  sha1 ? Blob.read(type, sha1) : {}
end