Created
June 26, 2009 19:16
-
-
Save ender672/136677 to your computer and use it in GitHub Desktop.
a sha1 based key/value in the filesystem store.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'digest/sha1' | |
class Sha1File | |
attr_reader :path | |
def initialize(sha1, base) | |
@base = base | |
@path = sha1_path sha1, base | |
@dir = File.dirname @path | |
end | |
# If a block is given, then we yield the file opened for writing. Otherwise | |
# we write the value parameter into the file. | |
def write(value=nil) | |
Dir.mkdir @base unless File.directory? @base | |
Dir.mkdir @dir unless File.directory? @dir | |
File.open(@path, 'wb') do |f| | |
block_given? ? yield(f) : f << value | |
end | |
end | |
def read | |
File.open(@path, 'r').read if file_exists? | |
end | |
def delete | |
value = read | |
if file_exists? | |
File.delete @path | |
Dir.unlink @dir if dir_empty? | |
end | |
return value | |
end | |
def self.clear(base) | |
dir_glob = File.join base, '??' | |
file_glob = File.join dir_glob, '*' | |
Dir.glob(file_glob).each{|f| File.unlink f} | |
Dir.glob(dir_glob).each{|d| Dir.unlink d} | |
end | |
private | |
def dir_empty? | |
!Dir.foreach(@dir){|e| break true unless /^.\.?$/ =~ e} | |
end | |
def file_exists? | |
File.file?(@path) | |
end | |
def sha1_path(sha1, base) | |
File.join base, sha1[0..1], sha1[2..-1] | |
end | |
end | |
# The sha1 of the key is calculated and the value is stored under that sha1 | |
class KeyValueStore | |
def initialize(options={}) | |
@base = options[:base] || 'key_value_store' | |
end | |
def [](key) | |
Sha1File.new(sha1(key), @base).read | |
end | |
def path(key) | |
Sha1File.new(sha1(key), @base).path | |
end | |
def []=(key, value) | |
Sha1File.new(sha1(key), @base).write value | |
end | |
def delete(key) | |
Sha1File.new(sha1(key), @base).delete | |
end | |
def clear | |
Sha1File.clear @base | |
end | |
private | |
def sha1(key) | |
Digest::SHA1.hexdigest key | |
end | |
end | |
# The sha1 of the value is calculated and the value is stored under that sha1 | |
class ObjectStore | |
def initialize(options={}) | |
@base = options[:base] || 'key_value_store' | |
end | |
def store(value) | |
sha1 = Digest::SHA1.hexdigest value | |
Sha1File.new(sha1, @base).write value | |
return sha1 | |
end | |
def retrieve(sha1, with_data_validation=nil) | |
value = Sha1File.new(sha1, @base).read | |
if with_data_validation | |
sha1_validation = Digest::SHA1.hexdigest value | |
if sha1 != sha1_validation | |
raise StandardError, "The object with sha1 #{sha1} is invalid. The data on the filesystem has sha1 #{sha1_validation}." | |
end | |
end | |
return value | |
end | |
def delete(sha1) | |
Sha1File.new(sha1, @base).delete | |
end | |
def clear | |
Sha1File.clear @base | |
end | |
end | |
if $0 == __FILE__ | |
s = KeyValueStore.new :base => 'temp/sha' | |
s['hay'] = 'is for horses' | |
s['you'] = 'are my hero' | |
p s['hay'] | |
p s['you'] | |
p s['uhoh'] | |
s.delete('hay') | |
s.delete('uhoh') | |
s.clear | |
o = ObjectStore.new :base => 'temp/obj' | |
sha1_a = o.store 'Ob la di Ob la Da' | |
sha1_b = o.store 'Life goes on... ra!' | |
p o.retrieve(sha1_a, true) | |
#o.delete sha1_a | |
#o.clear | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment