-
Notifications
You must be signed in to change notification settings - Fork 3
sandbox type id classifier
tora edited this page Feb 1, 2012
·
11 revisions
################################################################################ # castoro-common/type_id_classifier.rb ################################################################################ module Castoro class TypeIdClassifier def initialize args default = args.delete :default # assign the default value entries = parse args check_if_overwrap entries.keys @cache = Hash.new do |cache, type| # if the cache misses, examine the type and assign it range, converter = entries.find { |range, converter| range.cover? type } cache[ type ] = converter || default end end def converter_module type @cache[ type ] end private def parse args Hash.new.tap do |h| args.each do |key, value| value.split(',').each do |portion| if portion =~ /\A\s*(\d+)(?:\s*-\s*(\d+))?\s*\Z/ min, max = [$1, ($2 || $1)].map { |x| x.to_i } min <= max or raise ArgumentError, "starting value exceeds ending value in the Type ID range: #{portion}" h[ min..max ] = key else raise ArgumentError, "Invalid expression in the Type ID range: #{portion}" end end end end end def check_if_overwrap ranges loop do a = ranges.shift break if ranges.empty? ranges.each do |b| if a.cover? b.min or a.cover? b.max raise ArgumentError, "Two ranges overwrap each other: #{a} and #{b}" end end end end end end ################################################################################ # castoro-common/basket_key_converter.rb ################################################################################ # require 'castoro-common/type_id_classifier' module Castoro class BasketKeyConverter def initialize configuration args = parse configuration @classifier = TypeIdClassifier.new args end def path base_dir, basket @classifier.converter_module(basket.type).path base_dir, basket end def string basket @classifier.converter_module(basket.type).string basket end def converter_module type @classifier.converter_module type end private def parse configuration Hash.new.tap do |h| configuration.map do |key, value| if key == "Default" h[ :default ] = find_module value else h[ find_module( key ) ] = value end end end end def find_module name BasketKeyConverterModule.const_get(name) rescue raise ArgumentError, "Invalid basket key converter module name: #{name}" end end module BasketKeyConverterModule module Dec40Seq def path base_dir, basket "#{base_dir}/#{basket.type}/baskets/a/#{mid(basket)}/#{dir(basket)}" end def string basket sprintf '%d.%d.%d', basket.content, basket.type, basket.revision end # 654321 => 0/000/654 # 3210987654321 => 3210/987/654 def mid basket n = basket.content / 1000 n, c = n.divmod 1000 a, b = n.divmod 1000 sprintf '%d/%03d/%03d', a, b, c end alias dir string module_function :path, :string, :mid, :dir end module Hex64Seq def path base_dir, basket "#{base_dir}/#{basket.type}/baskets/a/#{mid(basket)}/#{dir(basket)}" end def string basket sprintf '0x%016x.%d.%d', basket.content, basket.type, basket.revision end # 0x0123456789abcdef => 0123/456/789/abc def mid basket e = basket.content >> 12 d = e >> 12 c = d >> 12 b = c >> 12 a = b >> 12 sprintf '%01x/%03x/%03x/%03x/%03x', (a & 0xf), (b & 0xfff), (c & 0xfff), (d & 0xfff), (e & 0xfff) end def dir basket sprintf '%016x.%d.%d', basket.content, basket.type, basket.revision end module_function :path, :string, :mid, :dir end end end ################################################################################ # castoro-common/basket_key.rb ################################################################################ module Castoro class BasketKey attr_reader :content, :type, :revision def initialize content, type, revision @content, @type, @revision = content, type, revision end end end ################################################################################ # castoro-peer/basket.rb ################################################################################ module Castoro module Peer class Basket attr_reader :content, :type, :revision def self.base_dir= base_dir @@base_dir = base_dir end def self.converter= converter @@converter = converter end def initialize content, type, revision @content, @type, @revision = content, type, revision @converter = @@converter.converter_module type end def to_s defined?(@s) ? @s : @s = @converter.string(self) end def path_w defined?(@w) ? @w : @w = create_temp_path("baskets/w") end def path_r defined?(@r) ? @r : @r = create_temp_path("baskets/r") end def path_a defined?(@a) ? @a : @a = @converter.path(@@base_dir, self) end def path_d defined?(@d) ? @d : @d = create_temp_path("baskets/d") end def path_c defined?(@c) ? @c : @c = create_temp_path("offline/canceled") end def path_c_with_hint path path.match( /\/([^\/]+)$/ ) @c = create_full_path("offline/canceled", $1) if ( File.exist? @c ) @c = mktemp( @c ) end @c end private def create_full_path part, dir unless defined? @time @time = Time.now.strftime("%Y%m%dT%H") end "#{@@base_dir}/#{@type}/#{part}/#{@time}/#{dir}" end def create_temp_path part unless defined? @dir @dir = @converter.dir self end mktemp create_full_path(part, @dir) end def mktemp path t = Time.new body = "#{path}.#{t.strftime('%Y%m%dT%H%M%S')}.#{'%03d' % (t.usec / 1000)}" offset = 1 big_number = Process.pid * Thread.current.object_id begin number = big_number / offset % 1000000 candidate = "#{body}.#{'%06d' % number}" return candidate unless File.exist? candidate offset = offset * 10 end until 1000000 < offset raise InternalServerError, "mktemp failed: #{path} for #{to_s}" end end end end ################################################################################ # examples ################################################################################ # require 'castoro-common/basket_key_converter' module Castoro configuration = { "Dec40Seq" => "1-999, 2000, 3000 - 3999", "Hex64Seq" => "1000-1999", "Default" => "Dec40Seq" } converter = BasketKeyConverter.new configuration samples = [ [ 654321, 1, 1 ], [ 3210987654321, 2000, 1 ], [ 1234567890, 3333, 1 ], [ 78901234, 3333, 1 ], [ 0xaaa, 1000, 1 ], [ 0x0123456789ABCDEF, 1000, 1 ], [ 0x00fedcba98765432, 1234, 5 ], [ 0x6789abcdef, 9999, 4 ], ] # require 'castoro-common/basket_key' puts "Gateway:" samples.each do |x| basket = BasketKey.new x[0], x[1], x[2] printf "%-30s => %s\n", converter.string(basket), converter.path("/expdsk", basket) end puts "" # require 'castoro-peer/basket' puts "Peer:" Peer::Basket.base_dir = "/expdsk" Peer::Basket.converter = converter samples.each do |x| basket = Peer::Basket.new x[0], x[1], x[2] printf "%-30s => %s\n", basket.to_s, basket.path_a if false printf "%-30s => %s\n", "", basket.path_w printf "%-30s => %s\n", "", basket.path_r printf "%-30s => %s\n", "", basket.path_d # printf "%-30s => %s\n", "", basket.path_c printf "%-30s => %s\n", "", basket.path_c_with_hint("/expdsk/1234/baskets/w/20120201T10/00fedcba98765432.1234.5.20120201T101337.648.011000") printf "%-30s => %s\n", "", basket.path_c end end end __END__ $ ruby type_id-40.rb Gateway: 654321.1.1 => /expdsk/1/baskets/a/0/000/654/654321.1.1 3210987654321.2000.1 => /expdsk/2000/baskets/a/3210/987/654/3210987654321.2000.1 1234567890.3333.1 => /expdsk/3333/baskets/a/1/234/567/1234567890.3333.1 78901234.3333.1 => /expdsk/3333/baskets/a/0/078/901/78901234.3333.1 0x0000000000000aaa.1000.1 => /expdsk/1000/baskets/a/0/000/000/000/000/0000000000000aaa.1000.1 0x0123456789abcdef.1000.1 => /expdsk/1000/baskets/a/0/123/456/789/abc/0123456789abcdef.1000.1 0x00fedcba98765432.1234.5 => /expdsk/1234/baskets/a/0/0fe/dcb/a98/765/00fedcba98765432.1234.5 444691369455.9999.4 => /expdsk/9999/baskets/a/444/691/369/444691369455.9999.4 Peer: 654321.1.1 => /expdsk/1/baskets/a/0/000/654/654321.1.1 3210987654321.2000.1 => /expdsk/2000/baskets/a/3210/987/654/3210987654321.2000.1 1234567890.3333.1 => /expdsk/3333/baskets/a/1/234/567/1234567890.3333.1 78901234.3333.1 => /expdsk/3333/baskets/a/0/078/901/78901234.3333.1 0x0000000000000aaa.1000.1 => /expdsk/1000/baskets/a/0/000/000/000/000/0000000000000aaa.1000.1 0x0123456789abcdef.1000.1 => /expdsk/1000/baskets/a/0/123/456/789/abc/0123456789abcdef.1000.1 0x00fedcba98765432.1234.5 => /expdsk/1234/baskets/a/0/0fe/dcb/a98/765/00fedcba98765432.1234.5 444691369455.9999.4 => /expdsk/9999/baskets/a/444/691/369/444691369455.9999.4 To convert .rb into html for github wiki: $ perl -pe 'BEGIN{print"<pre>\n"} s/</</g; s/>/>/g; END{print"</pre>\n"}' xxx.rb > xxx.html