higgs 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +208 -0
- data/LICENSE +26 -0
- data/README +2 -0
- data/Rakefile +75 -0
- data/bin/higgs_backup +67 -0
- data/bin/higgs_dump_index +43 -0
- data/bin/higgs_dump_jlog +42 -0
- data/bin/higgs_verify +37 -0
- data/lib/cgi/session/higgs.rb +72 -0
- data/lib/higgs/block.rb +192 -0
- data/lib/higgs/cache.rb +117 -0
- data/lib/higgs/dbm.rb +55 -0
- data/lib/higgs/exceptions.rb +31 -0
- data/lib/higgs/flock.rb +77 -0
- data/lib/higgs/index.rb +164 -0
- data/lib/higgs/jlog.rb +159 -0
- data/lib/higgs/lock.rb +189 -0
- data/lib/higgs/storage.rb +1086 -0
- data/lib/higgs/store.rb +228 -0
- data/lib/higgs/tar.rb +390 -0
- data/lib/higgs/thread.rb +370 -0
- data/lib/higgs/tman.rb +513 -0
- data/lib/higgs/utils/bman.rb +285 -0
- data/lib/higgs/utils.rb +22 -0
- data/lib/higgs/version.rb +21 -0
- data/lib/higgs.rb +59 -0
- data/misc/cache_bench/cache_bench.rb +43 -0
- data/misc/dbm_bench/.strc +8 -0
- data/misc/dbm_bench/Rakefile +78 -0
- data/misc/dbm_bench/dbm_multi_thread.rb +199 -0
- data/misc/dbm_bench/dbm_rnd_delete.rb +43 -0
- data/misc/dbm_bench/dbm_rnd_read.rb +44 -0
- data/misc/dbm_bench/dbm_rnd_update.rb +44 -0
- data/misc/dbm_bench/dbm_seq_read.rb +45 -0
- data/misc/dbm_bench/dbm_seq_write.rb +44 -0
- data/misc/dbm_bench/st_verify.rb +28 -0
- data/misc/io_bench/cksum_bench.rb +48 -0
- data/misc/io_bench/jlog_bench.rb +71 -0
- data/misc/io_bench/write_bench.rb +128 -0
- data/misc/thread_bench/lock_bench.rb +132 -0
- data/mkrdoc.rb +8 -0
- data/rdoc.yml +13 -0
- data/sample/count.rb +60 -0
- data/sample/dbmtest.rb +38 -0
- data/test/Rakefile +45 -0
- data/test/run.rb +32 -0
- data/test/test_block.rb +163 -0
- data/test/test_cache.rb +214 -0
- data/test/test_cgi_session.rb +142 -0
- data/test/test_flock.rb +162 -0
- data/test/test_index.rb +258 -0
- data/test/test_jlog.rb +180 -0
- data/test/test_lock.rb +320 -0
- data/test/test_online_backup.rb +169 -0
- data/test/test_storage.rb +439 -0
- data/test/test_storage_conf.rb +202 -0
- data/test/test_storage_init_opts.rb +89 -0
- data/test/test_store.rb +211 -0
- data/test/test_tar.rb +432 -0
- data/test/test_thread.rb +541 -0
- data/test/test_tman.rb +875 -0
- data/test/test_tman_init_opts.rb +56 -0
- data/test/test_utils_bman.rb +234 -0
- metadata +115 -0
| @@ -0,0 +1,132 @@ | |
| 1 | 
            +
            #!/usr/local/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # for ident(1)
         | 
| 4 | 
            +
            CVS_ID = '$Id: lock_bench.rb 559 2007-09-25 15:20:20Z toki $'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            $: << File.join(File.dirname($0), '..', '..', 'lib')
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'benchmark'
         | 
| 9 | 
            +
            require 'higgs/thread'
         | 
| 10 | 
            +
            require 'monitor'
         | 
| 11 | 
            +
            require 'sync'
         | 
| 12 | 
            +
            require 'thread'
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            loop_count = (ARGV.shift || '1000').to_i
         | 
| 15 | 
            +
            thread_count = (ARGV.shift || '10').to_i
         | 
| 16 | 
            +
            puts "#{$0}: LOOP:#{loop_count}, THREAD:#{thread_count}"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            Benchmark.bm(30) do |x|
         | 
| 19 | 
            +
              [ [ Mutex.new,   'Mutex' ],
         | 
| 20 | 
            +
                [ Monitor.new, 'Monitor' ],
         | 
| 21 | 
            +
                [ Higgs::ReadWriteLock.new.read_lock, 'ReadWriteLock (read:M)' ],
         | 
| 22 | 
            +
                [ Higgs::ReadWriteLock.new.write_lock, 'ReadWriteLock (write:M)' ]
         | 
| 23 | 
            +
              ].each do |m, name|
         | 
| 24 | 
            +
                barrier = Higgs::Barrier.new(thread_count + 1)
         | 
| 25 | 
            +
                th_grp = ThreadGroup.new
         | 
| 26 | 
            +
                thread_count.times do
         | 
| 27 | 
            +
                  th_grp.add Thread.new{
         | 
| 28 | 
            +
                    barrier.wait
         | 
| 29 | 
            +
                    loop_count.times do
         | 
| 30 | 
            +
                      m.synchronize{
         | 
| 31 | 
            +
                        # nothing to do.
         | 
| 32 | 
            +
                      }
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
                  }
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                x.report(name) {
         | 
| 38 | 
            +
                  barrier.wait
         | 
| 39 | 
            +
                  for t in th_grp.list
         | 
| 40 | 
            +
                    t.join
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                }
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              r_lock, w_lock = Higgs::ReadWriteLock.new.to_a
         | 
| 46 | 
            +
              barrier = Higgs::Barrier.new(thread_count + 1)
         | 
| 47 | 
            +
              th_grp = ThreadGroup.new
         | 
| 48 | 
            +
              (thread_count - 1).times do
         | 
| 49 | 
            +
                th_grp.add Thread.new{
         | 
| 50 | 
            +
                  barrier.wait
         | 
| 51 | 
            +
                  loop_count.times do
         | 
| 52 | 
            +
                    r_lock.synchronize{
         | 
| 53 | 
            +
                      # nothing to do.
         | 
| 54 | 
            +
                    }
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
                }
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
              th_grp.add Thread.new{
         | 
| 59 | 
            +
                barrier.wait
         | 
| 60 | 
            +
                loop_count.times do
         | 
| 61 | 
            +
                  w_lock.synchronize{
         | 
| 62 | 
            +
                    # nothing to do.
         | 
| 63 | 
            +
                  }
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              }
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              x.report('ReadWriteLock (read:M/write:1)') {
         | 
| 68 | 
            +
                barrier.wait
         | 
| 69 | 
            +
                for t in th_grp.list
         | 
| 70 | 
            +
                  t.join
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
              }
         | 
| 73 | 
            +
             | 
| 74 | 
            +
              [ [ Sync::SH, 'Sync (read:M)' ],
         | 
| 75 | 
            +
                [ Sync::EX, 'Sync (write:M)' ]
         | 
| 76 | 
            +
              ].each do |mode, name|
         | 
| 77 | 
            +
                s = Sync.new
         | 
| 78 | 
            +
                barrier = Higgs::Barrier.new(thread_count + 1)
         | 
| 79 | 
            +
                th_grp = ThreadGroup.new
         | 
| 80 | 
            +
                thread_count.times do
         | 
| 81 | 
            +
                  th_grp.add Thread.new{
         | 
| 82 | 
            +
                    barrier.wait
         | 
| 83 | 
            +
                    loop_count.times do
         | 
| 84 | 
            +
                      s.synchronize(mode) {
         | 
| 85 | 
            +
                        # nothing to do.
         | 
| 86 | 
            +
                      }
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
                  }
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                x.report(name) {
         | 
| 92 | 
            +
                  barrier.wait
         | 
| 93 | 
            +
                  for t in th_grp.list
         | 
| 94 | 
            +
                    t.join
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                }
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 99 | 
            +
              s = Sync.new
         | 
| 100 | 
            +
              barrier = Higgs::Barrier.new(thread_count + 1)
         | 
| 101 | 
            +
              th_grp = ThreadGroup.new
         | 
| 102 | 
            +
              (thread_count - 1).times do
         | 
| 103 | 
            +
                th_grp.add Thread.new{
         | 
| 104 | 
            +
                  barrier.wait
         | 
| 105 | 
            +
                  loop_count.times do
         | 
| 106 | 
            +
                    s.synchronize(Sync::SH) {
         | 
| 107 | 
            +
                      # nothing to do.
         | 
| 108 | 
            +
                    }
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                }
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
              th_grp.add Thread.new{
         | 
| 113 | 
            +
                barrier.wait
         | 
| 114 | 
            +
                loop_count.times do
         | 
| 115 | 
            +
                  s.synchronize(Sync::EX) {
         | 
| 116 | 
            +
                    # nothing to do.
         | 
| 117 | 
            +
                  }
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
              }
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              x.report('Sync (read:M/write:1)') {
         | 
| 122 | 
            +
                barrier.wait
         | 
| 123 | 
            +
                for t in th_grp.list
         | 
| 124 | 
            +
                  t.join
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
              }
         | 
| 127 | 
            +
            end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            # Local Variables:
         | 
| 130 | 
            +
            # mode: Ruby
         | 
| 131 | 
            +
            # indent-tabs-mode: nil
         | 
| 132 | 
            +
            # End:
         | 
    
        data/mkrdoc.rb
    ADDED
    
    
    
        data/rdoc.yml
    ADDED
    
    
    
        data/sample/count.rb
    ADDED
    
    | @@ -0,0 +1,60 @@ | |
| 1 | 
            +
            #!/usr/local/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'higgs'
         | 
| 4 | 
            +
            require 'higgs/thread'          # for Higgs::Barrier
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            num_of_write_threads = (ARGV.shift || '10').to_i
         | 
| 7 | 
            +
            num_of_count = (ARGV.shift || '100').to_i
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Higgs::Store.open('count') {|st|
         | 
| 10 | 
            +
              st.transaction(true) {|tx|
         | 
| 11 | 
            +
                puts "start - #{Time.now}"
         | 
| 12 | 
            +
                p tx[:count]
         | 
| 13 | 
            +
                puts ''
         | 
| 14 | 
            +
              }
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              th_grp = ThreadGroup.new
         | 
| 17 | 
            +
              barrier = Higgs::Barrier.new(num_of_write_threads + 2)
         | 
| 18 | 
            +
              is_print = true
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              num_of_write_threads.times do
         | 
| 21 | 
            +
                th_grp.add Thread.new{
         | 
| 22 | 
            +
                  barrier.wait
         | 
| 23 | 
            +
                  num_of_count.times do
         | 
| 24 | 
            +
                    st.transaction{|tx|
         | 
| 25 | 
            +
                      tx[:count] = 0 unless (tx.key? :count)
         | 
| 26 | 
            +
                      tx[:count] += 1
         | 
| 27 | 
            +
                    }
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
                }
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              th_read = Thread.new{
         | 
| 33 | 
            +
                barrier.wait
         | 
| 34 | 
            +
                while (is_print)
         | 
| 35 | 
            +
                  st.transaction(true) {|tx|
         | 
| 36 | 
            +
                    p tx[:count]
         | 
| 37 | 
            +
                  }
         | 
| 38 | 
            +
                  sleep(0.1)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              }
         | 
| 41 | 
            +
             | 
| 42 | 
            +
              barrier.wait
         | 
| 43 | 
            +
              for t in th_grp.list
         | 
| 44 | 
            +
                t.join
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              is_print = false
         | 
| 48 | 
            +
              th_read.join
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              st.transaction(true) {|tx|
         | 
| 51 | 
            +
                puts ''
         | 
| 52 | 
            +
                puts "last - #{Time.now}"
         | 
| 53 | 
            +
                p tx[:count]
         | 
| 54 | 
            +
              }
         | 
| 55 | 
            +
            }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            # Local Variables:
         | 
| 58 | 
            +
            # mode: Ruby
         | 
| 59 | 
            +
            # indent-tabs-mode: nil
         | 
| 60 | 
            +
            # End:
         | 
    
        data/sample/dbmtest.rb
    ADDED
    
    | @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            #!/usr/local/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'higgs'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Higgs::DBM.open('test') {|dbm|
         | 
| 6 | 
            +
              dbm.transaction{|tx|
         | 
| 7 | 
            +
                keys = tx.keys
         | 
| 8 | 
            +
                if (keys.length > 0) then
         | 
| 9 | 
            +
                  for k in keys
         | 
| 10 | 
            +
                    puts "-"
         | 
| 11 | 
            +
                    puts "key: #{k}"
         | 
| 12 | 
            +
                    puts "value: #{tx[k]}"
         | 
| 13 | 
            +
                    tx.each_property(k) do |name, value|
         | 
| 14 | 
            +
                      case (name)
         | 
| 15 | 
            +
                      when Symbol
         | 
| 16 | 
            +
                        puts "system_property[#{name}]: #{value}"
         | 
| 17 | 
            +
                      when String
         | 
| 18 | 
            +
                        puts "custom_property[#{name}]: #{value}"
         | 
| 19 | 
            +
                      else
         | 
| 20 | 
            +
                        raise "unexpected property name: #{name}"
         | 
| 21 | 
            +
                      end
         | 
| 22 | 
            +
                    end
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                else
         | 
| 25 | 
            +
                  tx['foobar'] = 'FB'
         | 
| 26 | 
            +
                  tx.set_property('foobar', 'number', 0)
         | 
| 27 | 
            +
                  tx['baz'] = 'BZ'
         | 
| 28 | 
            +
                  tx.set_property('baz', 'number', 1)
         | 
| 29 | 
            +
                  tx['quux'] = 'QX'
         | 
| 30 | 
            +
                  tx.set_property('quux', 'number', 2)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              }
         | 
| 33 | 
            +
            }
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            # Local Variables:
         | 
| 36 | 
            +
            # mode: Ruby
         | 
| 37 | 
            +
            # indent-tabs-mode: nil
         | 
| 38 | 
            +
            # End:
         | 
    
        data/test/Rakefile
    ADDED
    
    | @@ -0,0 +1,45 @@ | |
| 1 | 
            +
            # for ident(1)
         | 
| 2 | 
            +
            CVS_ID = '$Id: Rakefile 561 2007-09-26 15:46:49Z toki $'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            LIB_DIR = File.join(File.dirname(__FILE__), '..', 'lib')
         | 
| 5 | 
            +
            RCOV_DIR = File.join(File.dirname(__FILE__), 'coverage')
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            task :default => [ :test ]
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            task :test do
         | 
| 10 | 
            +
              ruby '-I', LIB_DIR, 'run.rb'
         | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            task :rcov do
         | 
| 14 | 
            +
              rm_rf RCOV_DIR
         | 
| 15 | 
            +
              sh 'rcov', '-I', LIB_DIR, '-x', 'rcov\.rb,run\.rb', 'run.rb'
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            task :optional do
         | 
| 19 | 
            +
              for opt_rb in Dir['optional/*.rb']
         | 
| 20 | 
            +
                symlnk_rb = File.basename(opt_rb)
         | 
| 21 | 
            +
                unless (File.symlink? symlnk_rb) then
         | 
| 22 | 
            +
                  ln_s opt_rb, symlnk_rb, :verbose => true
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            task :clean do
         | 
| 28 | 
            +
              rm_rf RCOV_DIR
         | 
| 29 | 
            +
            end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            task :clean_optional do
         | 
| 32 | 
            +
              for opt_rb in Dir['optional/*.rb']
         | 
| 33 | 
            +
                symlnk_rb = File.basename(opt_rb)
         | 
| 34 | 
            +
                rm_f symlnk_rb
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            rule '.test' => [ '.rb' ] do |t|
         | 
| 39 | 
            +
              ruby '-I', LIB_DIR, 'run.rb', '^' + Regexp.quote(t.source) + '$'
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            # Local Variables:
         | 
| 43 | 
            +
            # mode: Ruby
         | 
| 44 | 
            +
            # indent-tabs-mode: nil
         | 
| 45 | 
            +
            # End:
         | 
    
        data/test/run.rb
    ADDED
    
    | @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            #!/usr/local/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            $: << File.dirname(__FILE__)
         | 
| 4 | 
            +
            $: << File.join(File.dirname(__FILE__), '..', 'lib')
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # for ident(1)
         | 
| 7 | 
            +
            CVS_ID = '$Id: run.rb 575 2007-09-29 08:13:51Z toki $'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            mask = //                       # any match
         | 
| 10 | 
            +
            if ($0 == __FILE__) then
         | 
| 11 | 
            +
              if (ARGV.length > 0 && ARGV[0] !~ /^-/) then
         | 
| 12 | 
            +
                mask = Regexp.compile(ARGV.shift)
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            test_dir, this_name = File.split(__FILE__)
         | 
| 17 | 
            +
            for test_rb in Dir.entries(test_dir).sort
         | 
| 18 | 
            +
              case (test_rb)
         | 
| 19 | 
            +
              when this_name
         | 
| 20 | 
            +
                # skip
         | 
| 21 | 
            +
              when /^test_.*\.rb$/
         | 
| 22 | 
            +
                if (test_rb =~ mask) then
         | 
| 23 | 
            +
                  puts "load #{test_rb}"
         | 
| 24 | 
            +
                  require File.join(test_dir, test_rb)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            # Local Variables:
         | 
| 30 | 
            +
            # mode: Ruby
         | 
| 31 | 
            +
            # indent-tabs-mode: nil
         | 
| 32 | 
            +
            # End:
         | 
    
        data/test/test_block.rb
    ADDED
    
    | @@ -0,0 +1,163 @@ | |
| 1 | 
            +
            #!/usr/local/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'digest/sha2'
         | 
| 4 | 
            +
            require 'fileutils'
         | 
| 5 | 
            +
            require 'higgs/block'
         | 
| 6 | 
            +
            require 'test/unit'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Higgs::Test
         | 
| 9 | 
            +
              class BlockTest < Test::Unit::TestCase
         | 
| 10 | 
            +
                include Higgs::Block
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # for ident(1)
         | 
| 13 | 
            +
                CVS_ID = '$Id: test_block.rb 559 2007-09-25 15:20:20Z toki $'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def setup
         | 
| 16 | 
            +
                  @io = File.open('block.test_io', 'w+')
         | 
| 17 | 
            +
                  @io.binmode
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def teardown
         | 
| 21 | 
            +
                  @io.close unless @io.closed?
         | 
| 22 | 
            +
                  FileUtils.rm_f('block.test_io')
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def test_single_head_write_read
         | 
| 26 | 
            +
                  body = 'foo'
         | 
| 27 | 
            +
                  body_cksum_bin = Digest::SHA512.digest(body)
         | 
| 28 | 
            +
                  head_write(@io, 'FOO', body.length, 'SHA512', body_cksum_bin)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  @io.seek(0)
         | 
| 31 | 
            +
                  r = head_read(@io, 'FOO')
         | 
| 32 | 
            +
                  assert_equal(body.length,    r[0])
         | 
| 33 | 
            +
                  assert_equal('SHA512',       r[1])
         | 
| 34 | 
            +
                  assert_equal(body_cksum_bin, r[2])
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def test_single_block_write_read
         | 
| 38 | 
            +
                  body = 'foo'
         | 
| 39 | 
            +
                  block_write(@io, 'FOO', body)
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  @io.seek(0)
         | 
| 42 | 
            +
                  assert_equal(body, block_read(@io, 'FOO'))
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def test_many_block_write_read
         | 
| 46 | 
            +
                  data_list = (0..12).map{|i| 'Z' * 2**i }.map{|s| [ s[0..-2], s, s + 'Z' ] }.flatten
         | 
| 47 | 
            +
                  for s in data_list
         | 
| 48 | 
            +
                    block_write(@io, 'FOO', s)
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  i = 0
         | 
| 52 | 
            +
                  @io.seek(0)
         | 
| 53 | 
            +
                  while (s = block_read(@io, 'FOO'))
         | 
| 54 | 
            +
                    assert(! data_list.empty?, "nth:#{i}")
         | 
| 55 | 
            +
                    assert_equal(data_list.shift, s)
         | 
| 56 | 
            +
                  end
         | 
| 57 | 
            +
                  assert(data_list.empty?)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                def test_empty_read
         | 
| 61 | 
            +
                  assert_nil(head_read(@io, 'FOO'))
         | 
| 62 | 
            +
                  assert_nil(block_read(@io, 'FOO'))
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def test_head_read_BrokenError_short_read
         | 
| 66 | 
            +
                  @io.write("\x00")
         | 
| 67 | 
            +
                  @io.seek(0)
         | 
| 68 | 
            +
                  assert_raise(BrokenError) {
         | 
| 69 | 
            +
                    head_read(@io, 'FOO')
         | 
| 70 | 
            +
                  }
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def test_head_read_BrokenError_broken_head_block
         | 
| 74 | 
            +
                  body = 'foo'
         | 
| 75 | 
            +
                  body_cksum_bin = Digest::SHA512.digest(body)
         | 
| 76 | 
            +
                  head_write(@io, 'FOO', body.length, 'SHA512', body_cksum_bin)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  @io.seek(511)
         | 
| 79 | 
            +
                  @io.write("\xFF")
         | 
| 80 | 
            +
                  @io.seek(0)
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  assert_raise(BrokenError) {
         | 
| 83 | 
            +
                    head_read(@io, 'FOO')
         | 
| 84 | 
            +
                  }
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                def test_head_read_BrokenError_unknown_magic_symbol
         | 
| 88 | 
            +
                  body = 'foo'
         | 
| 89 | 
            +
                  body_cksum_bin = Digest::SHA512.digest(body)
         | 
| 90 | 
            +
                  head_write(@io, 'BAR', body.length, 'SHA512', body_cksum_bin)
         | 
| 91 | 
            +
                  @io.seek(0)
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                  assert_raise(BrokenError) {
         | 
| 94 | 
            +
                    head_read(@io, 'FOO')
         | 
| 95 | 
            +
                  }
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def test_block_read_BrokenError_short_unexpected_EOF_1
         | 
| 99 | 
            +
                  block_write(@io, 'FOO', 'foo')
         | 
| 100 | 
            +
                  @io.truncate(512)
         | 
| 101 | 
            +
                  @io.seek(0)
         | 
| 102 | 
            +
                  assert_raise(BrokenError) {
         | 
| 103 | 
            +
                    block_read(@io, 'FOO')
         | 
| 104 | 
            +
                  }
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def test_block_read_BrokenError_short_read_1
         | 
| 108 | 
            +
                  block_write(@io, 'FOO', 'foo')
         | 
| 109 | 
            +
                  @io.truncate(513)
         | 
| 110 | 
            +
                  @io.seek(0)
         | 
| 111 | 
            +
                  assert_raise(BrokenError) {
         | 
| 112 | 
            +
                    block_read(@io, 'FOO')
         | 
| 113 | 
            +
                  }
         | 
| 114 | 
            +
                end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                def test_block_read_BrokenError_short_unexpected_EOF_2
         | 
| 117 | 
            +
                  block_write(@io, 'FOO', 'foo')
         | 
| 118 | 
            +
                  @io.truncate(515)
         | 
| 119 | 
            +
                  @io.seek(0)
         | 
| 120 | 
            +
                  assert_raise(BrokenError) {
         | 
| 121 | 
            +
                    block_read(@io, 'FOO')
         | 
| 122 | 
            +
                  }
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                def test_block_read_BrokenError_short_read_2
         | 
| 126 | 
            +
                  block_write(@io, 'FOO', 'foo')
         | 
| 127 | 
            +
                  @io.truncate(1023)
         | 
| 128 | 
            +
                  @io.seek(0)
         | 
| 129 | 
            +
                  assert_raise(BrokenError) {
         | 
| 130 | 
            +
                    block_read(@io, 'FOO')
         | 
| 131 | 
            +
                  }
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def test_block_read_BrokenError_unknown_body_cksum_type
         | 
| 135 | 
            +
                  body = 'foo'
         | 
| 136 | 
            +
                  block_write(@io, 'FOO', body)
         | 
| 137 | 
            +
                  @io.seek(0)
         | 
| 138 | 
            +
                  head_write(@io, 'FOO', body.length, 'UNKNOWN', Digest::SHA512.digest(body))
         | 
| 139 | 
            +
                  @io.seek(0)
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                  assert_raise(BrokenError) {
         | 
| 142 | 
            +
                    block_read(@io, 'FOO')
         | 
| 143 | 
            +
                  }
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                def test_block_read_BrokenError_unknown_body_cksum_error
         | 
| 147 | 
            +
                  body = 'foo'
         | 
| 148 | 
            +
                  block_write(@io, 'FOO', body)
         | 
| 149 | 
            +
                  @io.seek(0)
         | 
| 150 | 
            +
                  head_write(@io, 'FOO', body.length, 'SHA512', '')
         | 
| 151 | 
            +
                  @io.seek(0)
         | 
| 152 | 
            +
             | 
| 153 | 
            +
                  assert_raise(BrokenError) {
         | 
| 154 | 
            +
                    block_read(@io, 'FOO')
         | 
| 155 | 
            +
                  }
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
              end
         | 
| 158 | 
            +
            end
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            # Local Variables:
         | 
| 161 | 
            +
            # mode: Ruby
         | 
| 162 | 
            +
            # indent-tabs-mode: nil
         | 
| 163 | 
            +
            # End:
         | 
    
        data/test/test_cache.rb
    ADDED
    
    | @@ -0,0 +1,214 @@ | |
| 1 | 
            +
            #!/usr/local/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'higgs/cache'
         | 
| 4 | 
            +
            require 'higgs/thread'
         | 
| 5 | 
            +
            require 'test/unit'
         | 
| 6 | 
            +
            require 'timeout'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            module Higgs::Test
         | 
| 9 | 
            +
              class LRUCacheTest < Test::Unit::TestCase
         | 
| 10 | 
            +
                include Higgs
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                # for ident(1)
         | 
| 13 | 
            +
                CVS_ID = '$Id: test_cache.rb 559 2007-09-25 15:20:20Z toki $'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                CACHE_LIMIT_SIZE = 10
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def setup
         | 
| 18 | 
            +
                  @cache = LRUCache.new(CACHE_LIMIT_SIZE)
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def test_store_and_fetch
         | 
| 22 | 
            +
                  @cache[:foo] = 'apple'
         | 
| 23 | 
            +
                  @cache[:bar] = 'banana'
         | 
| 24 | 
            +
                  @cache[:baz] = 'orange'
         | 
| 25 | 
            +
                  assert_equal('apple',  @cache[:foo])
         | 
| 26 | 
            +
                  assert_equal('banana', @cache[:bar])
         | 
| 27 | 
            +
                  assert_equal('orange', @cache[:baz])
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def test_fetch_not_defined_value
         | 
| 31 | 
            +
                  assert_nil(@cache[:foo])
         | 
| 32 | 
            +
                  assert_nil(@cache[:bar])
         | 
| 33 | 
            +
                  assert_nil(@cache[:baz])
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                def test_delete
         | 
| 37 | 
            +
                  @cache[:foo] = 'apple'
         | 
| 38 | 
            +
                  @cache[:bar] = 'banana'
         | 
| 39 | 
            +
                  @cache[:baz] = 'orange'
         | 
| 40 | 
            +
                  @cache.delete(:bar)
         | 
| 41 | 
            +
                  assert_equal('apple',  @cache[:foo])
         | 
| 42 | 
            +
                  assert_equal(nil,      @cache[:bar])
         | 
| 43 | 
            +
                  assert_equal('orange', @cache[:baz])
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def test_LRU_read
         | 
| 47 | 
            +
                  CACHE_LIMIT_SIZE.times do |i|
         | 
| 48 | 
            +
                    @cache[i] = i.to_s
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                  CACHE_LIMIT_SIZE.times do |i|
         | 
| 51 | 
            +
                    assert_equal(i.to_s, @cache[i], "#{i}")
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                  old_key = 0
         | 
| 55 | 
            +
                  last_key = CACHE_LIMIT_SIZE - 1
         | 
| 56 | 
            +
                  new_key = CACHE_LIMIT_SIZE
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                  @cache[new_key] = new_key.to_s
         | 
| 59 | 
            +
                  assert_equal(nil,           @cache[old_key])
         | 
| 60 | 
            +
                  assert_equal(last_key.to_s, @cache[last_key])
         | 
| 61 | 
            +
                  assert_equal(new_key.to_s,  @cache[new_key])
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def test_LRU_write
         | 
| 65 | 
            +
                  CACHE_LIMIT_SIZE.times do |i|
         | 
| 66 | 
            +
                    @cache[i] = i.to_s
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  (0...CACHE_LIMIT_SIZE).to_a.reverse_each do |i|
         | 
| 69 | 
            +
                    @cache[i] = i.to_s
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  old_key = CACHE_LIMIT_SIZE - 1
         | 
| 73 | 
            +
                  last_key = 0
         | 
| 74 | 
            +
                  new_key = CACHE_LIMIT_SIZE
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  @cache[new_key] = new_key.to_s
         | 
| 77 | 
            +
                  assert_equal(nil,           @cache[old_key])
         | 
| 78 | 
            +
                  assert_equal(last_key.to_s, @cache[last_key])
         | 
| 79 | 
            +
                  assert_equal(new_key.to_s,  @cache[new_key])
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
              end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
              class SharedWorkCacheTest < Test::Unit::TestCase
         | 
| 84 | 
            +
                include Higgs
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                # for ident(1)
         | 
| 87 | 
            +
                CVS_ID = '$Id: test_cache.rb 559 2007-09-25 15:20:20Z toki $'
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def setup
         | 
| 90 | 
            +
                  @calc_calls = 0
         | 
| 91 | 
            +
                  @cache = SharedWorkCache.new{|key| calc(key) }
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                def calc(n)
         | 
| 95 | 
            +
                  @calc_calls += 1
         | 
| 96 | 
            +
                  @s = 0                    # @s's scope is over multi-threading
         | 
| 97 | 
            +
                  for i in 1..n
         | 
| 98 | 
            +
                    @s += i
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                  @s
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def test_calc
         | 
| 104 | 
            +
                  assert_equal(1, calc(1))
         | 
| 105 | 
            +
                  assert_equal(1, @calc_calls)
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  assert_equal(3, calc(2))
         | 
| 108 | 
            +
                  assert_equal(2, @calc_calls)
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                  assert_equal(6, calc(3))
         | 
| 111 | 
            +
                  assert_equal(3, @calc_calls)
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                  assert_equal(10, calc(4))
         | 
| 114 | 
            +
                  assert_equal(4, @calc_calls)
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                  assert_equal(15, calc(5))
         | 
| 117 | 
            +
                  assert_equal(5, @calc_calls)
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                def test_fetch
         | 
| 121 | 
            +
                  100.times do |i|
         | 
| 122 | 
            +
                    assert_equal(1,  @cache[1], "loop(#{i})")
         | 
| 123 | 
            +
                    assert_equal(3,  @cache[2], "loop(#{i})")
         | 
| 124 | 
            +
                    assert_equal(6,  @cache[3], "loop(#{i})")
         | 
| 125 | 
            +
                    assert_equal(10, @cache[4], "loop(#{i})")
         | 
| 126 | 
            +
                    assert_equal(15, @cache[5], "loop(#{i})")
         | 
| 127 | 
            +
                    assert_equal(5, @calc_calls)
         | 
| 128 | 
            +
                  end
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def test_delete
         | 
| 132 | 
            +
                  assert_equal(false, @cache.delete(5))
         | 
| 133 | 
            +
                  assert_equal(15, @cache[5])
         | 
| 134 | 
            +
                  assert_equal(1, @calc_calls)
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                  assert_equal(true, @cache.delete(5))
         | 
| 137 | 
            +
                  assert_equal(15, @cache[5])
         | 
| 138 | 
            +
                  assert_equal(2, @calc_calls, 'reload')
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                NUM_OF_THREADS = 10
         | 
| 142 | 
            +
                WORK_COUNT = 10000
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                def calc_race_condition
         | 
| 145 | 
            +
                  barrier = Higgs::Barrier.new(NUM_OF_THREADS + 1)
         | 
| 146 | 
            +
                  th_grp = ThreadGroup.new
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                  result_list = [ nil ] * NUM_OF_THREADS
         | 
| 149 | 
            +
                  NUM_OF_THREADS.times{|i|  # `i' should be local scope of thread block
         | 
| 150 | 
            +
                    th_grp.add Thread.new{
         | 
| 151 | 
            +
                      barrier.wait
         | 
| 152 | 
            +
                      result_list[i] = calc(WORK_COUNT)
         | 
| 153 | 
            +
                    }
         | 
| 154 | 
            +
                  }
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                  barrier.wait
         | 
| 157 | 
            +
                  for t in th_grp.list
         | 
| 158 | 
            +
                    t.join
         | 
| 159 | 
            +
                  end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                  expected_value = calc(WORK_COUNT)
         | 
| 162 | 
            +
                  result_list.find{|v| v != expected_value }
         | 
| 163 | 
            +
                end
         | 
| 164 | 
            +
                private :calc_race_condition
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                def test_multi_thread_fetch
         | 
| 167 | 
            +
                  count = 0
         | 
| 168 | 
            +
                  timeout(10) {
         | 
| 169 | 
            +
                    begin
         | 
| 170 | 
            +
                      count += 1
         | 
| 171 | 
            +
                    end until (calc_race_condition)
         | 
| 172 | 
            +
                  }
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                  @calc_calls = 0
         | 
| 175 | 
            +
                  expected_result = calc(WORK_COUNT)
         | 
| 176 | 
            +
                  assert_equal(1, @calc_calls)
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                  count.times do |n|
         | 
| 179 | 
            +
                    barrier = Higgs::Barrier.new(NUM_OF_THREADS + 1)
         | 
| 180 | 
            +
                    th_grp = ThreadGroup.new
         | 
| 181 | 
            +
                    NUM_OF_THREADS.times{|i|  # `i' should be local scope of thread block
         | 
| 182 | 
            +
                      th_grp.add Thread.new{
         | 
| 183 | 
            +
                        barrier.wait
         | 
| 184 | 
            +
                        assert_equal(expected_result, @cache[WORK_COUNT], "#{n}th: th#{i}")
         | 
| 185 | 
            +
                      }
         | 
| 186 | 
            +
                    }
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                    barrier.wait
         | 
| 189 | 
            +
                    for t in th_grp.list
         | 
| 190 | 
            +
                      t.join
         | 
| 191 | 
            +
                    end
         | 
| 192 | 
            +
                    assert_equal(2, @calc_calls, "#{n}th")
         | 
| 193 | 
            +
                  end
         | 
| 194 | 
            +
                end
         | 
| 195 | 
            +
              end
         | 
| 196 | 
            +
             | 
| 197 | 
            +
              class SharedWorkCacheNoWorkBlockTest < Test::Unit::TestCase
         | 
| 198 | 
            +
                include Higgs
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                # for ident(1)
         | 
| 201 | 
            +
                CVS_ID = '$Id: test_cache.rb 559 2007-09-25 15:20:20Z toki $'
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                def test_no_work_block
         | 
| 204 | 
            +
                  assert_raise(RuntimeError) {
         | 
| 205 | 
            +
                    SharedWorkCache.new
         | 
| 206 | 
            +
                  }
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
              end
         | 
| 209 | 
            +
            end
         | 
| 210 | 
            +
             | 
| 211 | 
            +
            # Local Variables:
         | 
| 212 | 
            +
            # mode: Ruby
         | 
| 213 | 
            +
            # indent-tabs-mode: nil
         | 
| 214 | 
            +
            # End:
         |