oklahoma_mixer 0.1.0 → 0.2.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.rdoc +10 -0
 - data/TODO.rdoc +3 -3
 - data/lib/oklahoma_mixer.rb +14 -5
 - data/lib/oklahoma_mixer/b_tree_database.rb +185 -0
 - data/lib/oklahoma_mixer/b_tree_database/c.rb +45 -0
 - data/lib/oklahoma_mixer/cursor.rb +43 -0
 - data/lib/oklahoma_mixer/cursor/c.rb +45 -0
 - data/lib/oklahoma_mixer/fixed_length_database.rb +95 -0
 - data/lib/oklahoma_mixer/fixed_length_database/c.rb +62 -0
 - data/lib/oklahoma_mixer/hash_database.rb +84 -54
 - data/lib/oklahoma_mixer/hash_database/c.rb +3 -96
 - data/lib/oklahoma_mixer/utilities.rb +110 -5
 - data/test/b_tree_binary_data_test.rb +45 -0
 - data/test/b_tree_tuning_test.rb +132 -0
 - data/test/binary_data_test.rb +3 -13
 - data/test/cursor_based_iteration_test.rb +151 -0
 - data/test/duplicate_storage_test.rb +107 -0
 - data/test/fixed_length_tuning_test.rb +77 -0
 - data/test/getting_and_setting_by_id_test.rb +288 -0
 - data/test/getting_and_setting_keys_test.rb +37 -3
 - data/test/iteration_test.rb +2 -76
 - data/test/key_range_test.rb +161 -0
 - data/test/order_test.rb +122 -0
 - data/test/shared_binary_data.rb +14 -0
 - data/test/shared_iteration.rb +99 -0
 - data/test/shared_tuning.rb +91 -0
 - data/test/test_helper.rb +10 -11
 - data/test/top_level_interface_test.rb +12 -0
 - data/test/tuning_test.rb +11 -87
 - metadata +27 -2
 
    
        data/CHANGELOG.rdoc
    CHANGED
    
    | 
         @@ -2,6 +2,16 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            Below is a complete listing of changes for each revision of Oklahoma Mixer.
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
            == 0.2.0
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            * Added a to_hash() iterator that can preserve defaults
         
     | 
| 
      
 8 
     | 
    
         
            +
            * Added B+Tree Database support (order functions, key ranges,
         
     | 
| 
      
 9 
     | 
    
         
            +
              and duplicate storages)
         
     | 
| 
      
 10 
     | 
    
         
            +
            * Added Fixed-length Database (indexing and iterating by ID's, support for
         
     | 
| 
      
 11 
     | 
    
         
            +
              special ID constants, and size limits)
         
     | 
| 
      
 12 
     | 
    
         
            +
            * Fixed a bug that could cause Ruby to crash during GC after storing a value
         
     | 
| 
      
 13 
     | 
    
         
            +
              with the duplication handler block
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       5 
15 
     | 
    
         
             
            == 0.1.0
         
     | 
| 
       6 
16 
     | 
    
         | 
| 
       7 
17 
     | 
    
         
             
            * Initial public release with Hash Database support
         
     | 
    
        data/TODO.rdoc
    CHANGED
    
    | 
         @@ -3,9 +3,9 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            The following is a list of planned expansions for Oklahoma Mixer in the order I
         
     | 
| 
       4 
4 
     | 
    
         
             
            intend to address them.
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            1. Add support for  
     | 
| 
       7 
     | 
    
         
            -
            2.  
     | 
| 
       8 
     | 
    
         
            -
            3.  
     | 
| 
      
 6 
     | 
    
         
            +
            1. Add support for Table Databases
         
     | 
| 
      
 7 
     | 
    
         
            +
            2. Ensure Ruby 1.9 compatibility
         
     | 
| 
      
 8 
     | 
    
         
            +
            3. Write API documentation
         
     | 
| 
       9 
9 
     | 
    
         
             
            4. Add support for Tokyo Tyrant
         
     | 
| 
       10 
10 
     | 
    
         
             
            5. Add support for Tokyo Dystopia
         
     | 
| 
       11 
11 
     | 
    
         
             
            6. Include some higher level abstractions like mixed tables, queues, and shards
         
     | 
    
        data/lib/oklahoma_mixer.rb
    CHANGED
    
    | 
         @@ -7,18 +7,27 @@ require "oklahoma_mixer/extensible_string/c" 
     | 
|
| 
       7 
7 
     | 
    
         
             
            require "oklahoma_mixer/extensible_string"
         
     | 
| 
       8 
8 
     | 
    
         
             
            require "oklahoma_mixer/array_list/c"
         
     | 
| 
       9 
9 
     | 
    
         
             
            require "oklahoma_mixer/array_list"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require "oklahoma_mixer/cursor/c"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "oklahoma_mixer/cursor"
         
     | 
| 
       10 
12 
     | 
    
         | 
| 
       11 
13 
     | 
    
         
             
            require "oklahoma_mixer/hash_database/c"
         
     | 
| 
       12 
14 
     | 
    
         
             
            require "oklahoma_mixer/hash_database"
         
     | 
| 
      
 15 
     | 
    
         
            +
            require "oklahoma_mixer/b_tree_database/c"
         
     | 
| 
      
 16 
     | 
    
         
            +
            require "oklahoma_mixer/b_tree_database"
         
     | 
| 
      
 17 
     | 
    
         
            +
            require "oklahoma_mixer/fixed_length_database/c"
         
     | 
| 
      
 18 
     | 
    
         
            +
            require "oklahoma_mixer/fixed_length_database"
         
     | 
| 
       13 
19 
     | 
    
         | 
| 
       14 
20 
     | 
    
         
             
            module OklahomaMixer
         
     | 
| 
       15 
     | 
    
         
            -
              VERSION = "0. 
     | 
| 
      
 21 
     | 
    
         
            +
              VERSION = "0.2.0"
         
     | 
| 
       16 
22 
     | 
    
         | 
| 
       17 
23 
     | 
    
         
             
              def self.open(path, *args)
         
     | 
| 
       18 
     | 
    
         
            -
                 
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 24 
     | 
    
         
            +
                db_class = case File.extname(path).downcase
         
     | 
| 
      
 25 
     | 
    
         
            +
                           when ".tch" then HashDatabase
         
     | 
| 
      
 26 
     | 
    
         
            +
                           when ".tcb" then BTreeDatabase
         
     | 
| 
      
 27 
     | 
    
         
            +
                           when ".tcf" then FixedLengthDatabase
         
     | 
| 
      
 28 
     | 
    
         
            +
                           else             fail ArgumentError, "unsupported database type"
         
     | 
| 
      
 29 
     | 
    
         
            +
                           end
         
     | 
| 
      
 30 
     | 
    
         
            +
                db       = db_class.new(path, *args)
         
     | 
| 
       22 
31 
     | 
    
         
             
                if block_given?
         
     | 
| 
       23 
32 
     | 
    
         
             
                  begin
         
     | 
| 
       24 
33 
     | 
    
         
             
                    yield db
         
     | 
| 
         @@ -0,0 +1,185 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module OklahomaMixer
         
     | 
| 
      
 2 
     | 
    
         
            +
              class BTreeDatabase < HashDatabase
         
     | 
| 
      
 3 
     | 
    
         
            +
                ###################
         
     | 
| 
      
 4 
     | 
    
         
            +
                ### File System ###
         
     | 
| 
      
 5 
     | 
    
         
            +
                ###################
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                def optimize(options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  try( options[:tune] ? :tune : :optimize,
         
     | 
| 
      
 9 
     | 
    
         
            +
                       options.fetch(:lmemb,  0).to_i,
         
     | 
| 
      
 10 
     | 
    
         
            +
                       options.fetch(:nmemb,  0).to_i,
         
     | 
| 
      
 11 
     | 
    
         
            +
                       options.fetch(:bnum,   0).to_i,
         
     | 
| 
      
 12 
     | 
    
         
            +
                       options.fetch(:apow,  -1).to_i,
         
     | 
| 
      
 13 
     | 
    
         
            +
                       options.fetch(:fpow,  -1).to_i,
         
     | 
| 
      
 14 
     | 
    
         
            +
                       to_enum_int(options.fetch(:opts, 0xFF), :opt) )
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                ################################
         
     | 
| 
      
 18 
     | 
    
         
            +
                ### Getting and Setting Keys ###
         
     | 
| 
      
 19 
     | 
    
         
            +
                ################################
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def store(key, value, mode = nil)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if mode == :dup
         
     | 
| 
      
 23 
     | 
    
         
            +
                    try(:putdup, cast_key_in(key), cast_value_in(value))
         
     | 
| 
      
 24 
     | 
    
         
            +
                    value
         
     | 
| 
      
 25 
     | 
    
         
            +
                  else
         
     | 
| 
      
 26 
     | 
    
         
            +
                    super
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
                
         
     | 
| 
      
 30 
     | 
    
         
            +
                def keys(options = { })
         
     | 
| 
      
 31 
     | 
    
         
            +
                  if options.include? :range
         
     | 
| 
      
 32 
     | 
    
         
            +
                    warn "range supersedes prefix" if options[:prefix]
         
     | 
| 
      
 33 
     | 
    
         
            +
                    range = options[:range]
         
     | 
| 
      
 34 
     | 
    
         
            +
                    fail ArgumentError, "Range expected" unless range.is_a? Range
         
     | 
| 
      
 35 
     | 
    
         
            +
                    start          = cast_key_in(range.first)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    include_start  = !options.fetch(:exclude_start, false)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    finish         = cast_key_in(range.last)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    include_finish = !range.exclude_end?
         
     | 
| 
      
 39 
     | 
    
         
            +
                    limit          = options.fetch(:limit, -1)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 41 
     | 
    
         
            +
                      list = ArrayList.new( lib.range( @db,
         
     | 
| 
      
 42 
     | 
    
         
            +
                                                       *[ start,  include_start,
         
     | 
| 
      
 43 
     | 
    
         
            +
                                                          finish, include_finish,
         
     | 
| 
      
 44 
     | 
    
         
            +
                                                          limit ].flatten ) )
         
     | 
| 
      
 45 
     | 
    
         
            +
                      list.to_a
         
     | 
| 
      
 46 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 47 
     | 
    
         
            +
                      list.free if list
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  else
         
     | 
| 
      
 50 
     | 
    
         
            +
                    super
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def values(key = nil)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  if key.nil?
         
     | 
| 
      
 56 
     | 
    
         
            +
                    super()
         
     | 
| 
      
 57 
     | 
    
         
            +
                  else
         
     | 
| 
      
 58 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 59 
     | 
    
         
            +
                      pointer = try( :get4, cast_key_in(key),
         
     | 
| 
      
 60 
     | 
    
         
            +
                                     :failure  => lambda { |ptr| ptr.address.zero? },
         
     | 
| 
      
 61 
     | 
    
         
            +
                                     :no_error => {22 => nil} )
         
     | 
| 
      
 62 
     | 
    
         
            +
                      if pointer.nil?
         
     | 
| 
      
 63 
     | 
    
         
            +
                        [ ]
         
     | 
| 
      
 64 
     | 
    
         
            +
                      else
         
     | 
| 
      
 65 
     | 
    
         
            +
                        list = ArrayList.new(pointer)
         
     | 
| 
      
 66 
     | 
    
         
            +
                        list.to_a
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 69 
     | 
    
         
            +
                      list.free if list
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
                
         
     | 
| 
      
 74 
     | 
    
         
            +
                def delete(key, mode = nil, &missing_handler)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  if mode == :dup
         
     | 
| 
      
 76 
     | 
    
         
            +
                    values = values(key)
         
     | 
| 
      
 77 
     | 
    
         
            +
                    if try(:out3, cast_key_in(key), :no_error => {22 => false})
         
     | 
| 
      
 78 
     | 
    
         
            +
                      values
         
     | 
| 
      
 79 
     | 
    
         
            +
                    else
         
     | 
| 
      
 80 
     | 
    
         
            +
                      missing_handler ? missing_handler[key] : values
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  else
         
     | 
| 
      
 83 
     | 
    
         
            +
                    super(key, &missing_handler)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  end
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def size(key = nil)
         
     | 
| 
      
 88 
     | 
    
         
            +
                  if key.nil?
         
     | 
| 
      
 89 
     | 
    
         
            +
                    super()
         
     | 
| 
      
 90 
     | 
    
         
            +
                  else
         
     | 
| 
      
 91 
     | 
    
         
            +
                    try(:vnum, cast_key_in(key), :failure => 0, :no_error => {22 => 0})
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
                alias_method :length, :size
         
     | 
| 
      
 95 
     | 
    
         
            +
                
         
     | 
| 
      
 96 
     | 
    
         
            +
                #################
         
     | 
| 
      
 97 
     | 
    
         
            +
                ### Iteration ###
         
     | 
| 
      
 98 
     | 
    
         
            +
                #################
         
     | 
| 
      
 99 
     | 
    
         
            +
                
         
     | 
| 
      
 100 
     | 
    
         
            +
                def each_key(start = nil)
         
     | 
| 
      
 101 
     | 
    
         
            +
                  cursor_in_loop(start) do |iterator|
         
     | 
| 
      
 102 
     | 
    
         
            +
                    throw(:finish_iteration) unless key = iterator.key
         
     | 
| 
      
 103 
     | 
    
         
            +
                    yield key
         
     | 
| 
      
 104 
     | 
    
         
            +
                  end
         
     | 
| 
      
 105 
     | 
    
         
            +
                end
         
     | 
| 
      
 106 
     | 
    
         
            +
                
         
     | 
| 
      
 107 
     | 
    
         
            +
                def each(start = nil)
         
     | 
| 
      
 108 
     | 
    
         
            +
                  cursor_in_loop(start) do |iterator|
         
     | 
| 
      
 109 
     | 
    
         
            +
                    throw(:finish_iteration) unless key_and_value = iterator.key_and_value
         
     | 
| 
      
 110 
     | 
    
         
            +
                    yield key_and_value
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
      
 112 
     | 
    
         
            +
                end
         
     | 
| 
      
 113 
     | 
    
         
            +
                alias_method :each_pair, :each
         
     | 
| 
      
 114 
     | 
    
         
            +
                
         
     | 
| 
      
 115 
     | 
    
         
            +
                def reverse_each(start = nil)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  cursor_in_loop(start, :reverse) do |iterator|
         
     | 
| 
      
 117 
     | 
    
         
            +
                    throw(:finish_iteration) unless key_and_value = iterator.key_and_value
         
     | 
| 
      
 118 
     | 
    
         
            +
                    yield key_and_value
         
     | 
| 
      
 119 
     | 
    
         
            +
                  end
         
     | 
| 
      
 120 
     | 
    
         
            +
                end
         
     | 
| 
      
 121 
     | 
    
         
            +
                
         
     | 
| 
      
 122 
     | 
    
         
            +
                def each_value(start = nil)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  cursor_in_loop(start) do |iterator|
         
     | 
| 
      
 124 
     | 
    
         
            +
                    throw(:finish_iteration) unless value = iterator.value
         
     | 
| 
      
 125 
     | 
    
         
            +
                    yield value
         
     | 
| 
      
 126 
     | 
    
         
            +
                  end
         
     | 
| 
      
 127 
     | 
    
         
            +
                end
         
     | 
| 
      
 128 
     | 
    
         
            +
                
         
     | 
| 
      
 129 
     | 
    
         
            +
                def delete_if(start = nil)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  cursor(start) do |iterator|
         
     | 
| 
      
 131 
     | 
    
         
            +
                    loop do
         
     | 
| 
      
 132 
     | 
    
         
            +
                      break unless key_and_value = iterator.key_and_value
         
     | 
| 
      
 133 
     | 
    
         
            +
                      break unless iterator.send(yield(*key_and_value) ? :delete : :next)
         
     | 
| 
      
 134 
     | 
    
         
            +
                    end
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
                
         
     | 
| 
      
 138 
     | 
    
         
            +
                #######
         
     | 
| 
      
 139 
     | 
    
         
            +
                private
         
     | 
| 
      
 140 
     | 
    
         
            +
                #######
         
     | 
| 
      
 141 
     | 
    
         
            +
                
         
     | 
| 
      
 142 
     | 
    
         
            +
                def tune(options)
         
     | 
| 
      
 143 
     | 
    
         
            +
                  super
         
     | 
| 
      
 144 
     | 
    
         
            +
                  if cmpfunc = options[:cmpfunc]
         
     | 
| 
      
 145 
     | 
    
         
            +
                    callback = lambda { |a_pointer, a_size, b_pointer, b_size, _|
         
     | 
| 
      
 146 
     | 
    
         
            +
                      a = a_pointer.get_bytes(0, a_size)
         
     | 
| 
      
 147 
     | 
    
         
            +
                      b = b_pointer.get_bytes(0, b_size)
         
     | 
| 
      
 148 
     | 
    
         
            +
                      cmpfunc[a, b]
         
     | 
| 
      
 149 
     | 
    
         
            +
                    }
         
     | 
| 
      
 150 
     | 
    
         
            +
                    try(:setcmpfunc, callback, nil)
         
     | 
| 
      
 151 
     | 
    
         
            +
                  end
         
     | 
| 
      
 152 
     | 
    
         
            +
                  if options.values_at(:lmemb, :nmemb, :bnum, :apow, :fpow, :opts).any?
         
     | 
| 
      
 153 
     | 
    
         
            +
                    optimize(options.merge(:tune => true))
         
     | 
| 
      
 154 
     | 
    
         
            +
                  end
         
     | 
| 
      
 155 
     | 
    
         
            +
                  if options.values_at(:lcnum, :ncnum).any?
         
     | 
| 
      
 156 
     | 
    
         
            +
                    setcache(options)
         
     | 
| 
      
 157 
     | 
    
         
            +
                  end
         
     | 
| 
      
 158 
     | 
    
         
            +
                end
         
     | 
| 
      
 159 
     | 
    
         
            +
                
         
     | 
| 
      
 160 
     | 
    
         
            +
                def setcache(options)
         
     | 
| 
      
 161 
     | 
    
         
            +
                  try( :setcache,
         
     | 
| 
      
 162 
     | 
    
         
            +
                       options.fetch(:lcnum, 0).to_i,
         
     | 
| 
      
 163 
     | 
    
         
            +
                       options.fetch(:ncnum, 0).to_i )
         
     | 
| 
      
 164 
     | 
    
         
            +
                end
         
     | 
| 
      
 165 
     | 
    
         
            +
                
         
     | 
| 
      
 166 
     | 
    
         
            +
                def cursor(start = nil, reverse = false)
         
     | 
| 
      
 167 
     | 
    
         
            +
                  cursor = Cursor.new(@db, start.nil? ? start : cast_key_in(start), reverse)
         
     | 
| 
      
 168 
     | 
    
         
            +
                  yield cursor
         
     | 
| 
      
 169 
     | 
    
         
            +
                  self
         
     | 
| 
      
 170 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 171 
     | 
    
         
            +
                  cursor.free if cursor
         
     | 
| 
      
 172 
     | 
    
         
            +
                end
         
     | 
| 
      
 173 
     | 
    
         
            +
                
         
     | 
| 
      
 174 
     | 
    
         
            +
                def cursor_in_loop(start = nil, reverse = false)
         
     | 
| 
      
 175 
     | 
    
         
            +
                  cursor(start, reverse) do |iterator|
         
     | 
| 
      
 176 
     | 
    
         
            +
                    catch(:finish_iteration) do
         
     | 
| 
      
 177 
     | 
    
         
            +
                      loop do
         
     | 
| 
      
 178 
     | 
    
         
            +
                        yield iterator
         
     | 
| 
      
 179 
     | 
    
         
            +
                        break unless iterator.next
         
     | 
| 
      
 180 
     | 
    
         
            +
                      end
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
                  end
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
              end
         
     | 
| 
      
 185 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module OklahomaMixer
         
     | 
| 
      
 2 
     | 
    
         
            +
              class BTreeDatabase < HashDatabase
         
     | 
| 
      
 3 
     | 
    
         
            +
                module C  # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend OklahomaMixer::Utilities::FFIDSL
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  prefix :tcbdb
         
     | 
| 
      
 7 
     | 
    
         
            +
                  
         
     | 
| 
      
 8 
     | 
    
         
            +
                  def_hash_database_consts_and_funcs
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  call :name    => :TCCMP,
         
     | 
| 
      
 11 
     | 
    
         
            +
                       :args    => [:pointer, :int, :pointer, :int, :pointer],
         
     | 
| 
      
 12 
     | 
    
         
            +
                       :returns => :int
         
     | 
| 
      
 13 
     | 
    
         
            +
                  func :name    => :setcmpfunc,
         
     | 
| 
      
 14 
     | 
    
         
            +
                       :args    => [:pointer, :TCCMP, :pointer],
         
     | 
| 
      
 15 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 16 
     | 
    
         
            +
                  func :name    => :tune,
         
     | 
| 
      
 17 
     | 
    
         
            +
                       :args    => [:pointer, :int32, :int32, :int64, :int8, :int8, OPTS],
         
     | 
| 
      
 18 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 19 
     | 
    
         
            +
                  func :name    => :setcache,
         
     | 
| 
      
 20 
     | 
    
         
            +
                       :args    => [:pointer, :int32, :int32],
         
     | 
| 
      
 21 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 22 
     | 
    
         
            +
                  func :name    => :optimize,
         
     | 
| 
      
 23 
     | 
    
         
            +
                       :args    => [:pointer, :int32, :int32, :int64, :int8, :int8, OPTS],
         
     | 
| 
      
 24 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  func :name    => :putdup,
         
     | 
| 
      
 27 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :int, :pointer, :int],
         
     | 
| 
      
 28 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 29 
     | 
    
         
            +
                  func :name    => :out3,
         
     | 
| 
      
 30 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :int],
         
     | 
| 
      
 31 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 32 
     | 
    
         
            +
                  func :name    => :get4,
         
     | 
| 
      
 33 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :int],
         
     | 
| 
      
 34 
     | 
    
         
            +
                       :returns => :pointer
         
     | 
| 
      
 35 
     | 
    
         
            +
                  func :name    => :vnum,
         
     | 
| 
      
 36 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :int],
         
     | 
| 
      
 37 
     | 
    
         
            +
                       :returns => :int
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  func :name    => :range,
         
     | 
| 
      
 40 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :int, :bool, :pointer, :int, :bool,
         
     | 
| 
      
 41 
     | 
    
         
            +
                                    :int],
         
     | 
| 
      
 42 
     | 
    
         
            +
                       :returns => :pointer
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,43 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module OklahomaMixer
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Cursor  # :nodoc:
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(b_tree_pointer, start = nil, reverse = false)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @pointer = C.new(b_tree_pointer)
         
     | 
| 
      
 5 
     | 
    
         
            +
                  @reverse = reverse
         
     | 
| 
      
 6 
     | 
    
         
            +
                  if start
         
     | 
| 
      
 7 
     | 
    
         
            +
                    C.jump(@pointer, *start)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  else
         
     | 
| 
      
 9 
     | 
    
         
            +
                    C.send(@reverse ? :last : :first, @pointer)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                def key
         
     | 
| 
      
 14 
     | 
    
         
            +
                  C.read_from_func(:key, @pointer)
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                def value
         
     | 
| 
      
 18 
     | 
    
         
            +
                  C.read_from_func(:val, @pointer)
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
                def key_and_value
         
     | 
| 
      
 22 
     | 
    
         
            +
                  Utilities.temp_xstr do |key|
         
     | 
| 
      
 23 
     | 
    
         
            +
                    Utilities.temp_xstr do |value|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      if C.rec(@pointer, key.pointer, value.pointer)
         
     | 
| 
      
 25 
     | 
    
         
            +
                        [key.to_s, value.to_s]
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                
         
     | 
| 
      
 31 
     | 
    
         
            +
                def next
         
     | 
| 
      
 32 
     | 
    
         
            +
                  C.send(@reverse ? :prev : :next, @pointer)
         
     | 
| 
      
 33 
     | 
    
         
            +
                end
         
     | 
| 
      
 34 
     | 
    
         
            +
                
         
     | 
| 
      
 35 
     | 
    
         
            +
                def delete
         
     | 
| 
      
 36 
     | 
    
         
            +
                  C.out(@pointer)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
                
         
     | 
| 
      
 39 
     | 
    
         
            +
                def free
         
     | 
| 
      
 40 
     | 
    
         
            +
                  C.del(@pointer)
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module OklahomaMixer
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Cursor
         
     | 
| 
      
 3 
     | 
    
         
            +
                module C  # :nodoc:
         
     | 
| 
      
 4 
     | 
    
         
            +
                  extend OklahomaMixer::Utilities::FFIDSL
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  prefix :tcbdbcur
         
     | 
| 
      
 7 
     | 
    
         
            +
                  
         
     | 
| 
      
 8 
     | 
    
         
            +
                  func :name    => :new,
         
     | 
| 
      
 9 
     | 
    
         
            +
                       :args    => :pointer,
         
     | 
| 
      
 10 
     | 
    
         
            +
                       :returns => :pointer
         
     | 
| 
      
 11 
     | 
    
         
            +
                  func :name    => :del,
         
     | 
| 
      
 12 
     | 
    
         
            +
                       :args    => :pointer
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  func :name    => :first,
         
     | 
| 
      
 15 
     | 
    
         
            +
                       :args    => :pointer,
         
     | 
| 
      
 16 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 17 
     | 
    
         
            +
                  func :name    => :last,
         
     | 
| 
      
 18 
     | 
    
         
            +
                       :args    => :pointer,
         
     | 
| 
      
 19 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 20 
     | 
    
         
            +
                  func :name    => :jump,
         
     | 
| 
      
 21 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :int],
         
     | 
| 
      
 22 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 23 
     | 
    
         
            +
                  func :name    => :next,
         
     | 
| 
      
 24 
     | 
    
         
            +
                       :args    => :pointer,
         
     | 
| 
      
 25 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 26 
     | 
    
         
            +
                  func :name    => :prev,
         
     | 
| 
      
 27 
     | 
    
         
            +
                       :args    => :pointer,
         
     | 
| 
      
 28 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  func :name    => :key,
         
     | 
| 
      
 31 
     | 
    
         
            +
                       :args    => [:pointer, :pointer],
         
     | 
| 
      
 32 
     | 
    
         
            +
                       :returns => :pointer
         
     | 
| 
      
 33 
     | 
    
         
            +
                  func :name    => :val,
         
     | 
| 
      
 34 
     | 
    
         
            +
                       :args    => [:pointer, :pointer],
         
     | 
| 
      
 35 
     | 
    
         
            +
                       :returns => :pointer
         
     | 
| 
      
 36 
     | 
    
         
            +
                  func :name    => :rec,
         
     | 
| 
      
 37 
     | 
    
         
            +
                       :args    => [:pointer, :pointer, :pointer],
         
     | 
| 
      
 38 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  func :name    => :out,
         
     | 
| 
      
 41 
     | 
    
         
            +
                       :args    => :pointer,
         
     | 
| 
      
 42 
     | 
    
         
            +
                       :returns => :bool
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,95 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module OklahomaMixer
         
     | 
| 
      
 2 
     | 
    
         
            +
              class FixedLengthDatabase < HashDatabase
         
     | 
| 
      
 3 
     | 
    
         
            +
                ###################
         
     | 
| 
      
 4 
     | 
    
         
            +
                ### File System ###
         
     | 
| 
      
 5 
     | 
    
         
            +
                ###################
         
     | 
| 
      
 6 
     | 
    
         
            +
                
         
     | 
| 
      
 7 
     | 
    
         
            +
                def optimize(options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  try( options[:tune] ? :tune : :optimize,
         
     | 
| 
      
 9 
     | 
    
         
            +
                       options.fetch(:width,  0).to_i,
         
     | 
| 
      
 10 
     | 
    
         
            +
                       options.fetch(:limsiz, 0).to_i  )
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                def defrag(steps = 0)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # do nothing:  not needed, but provided for a consistent interface
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
                
         
     | 
| 
      
 17 
     | 
    
         
            +
                ################################
         
     | 
| 
      
 18 
     | 
    
         
            +
                ### Getting and Setting Keys ###
         
     | 
| 
      
 19 
     | 
    
         
            +
                ################################
         
     | 
| 
      
 20 
     | 
    
         
            +
                
         
     | 
| 
      
 21 
     | 
    
         
            +
                def keys(options = { })
         
     | 
| 
      
 22 
     | 
    
         
            +
                  if options.include? :range
         
     | 
| 
      
 23 
     | 
    
         
            +
                    warn "range supersedes prefix" if options[:prefix]
         
     | 
| 
      
 24 
     | 
    
         
            +
                    range = options[:range]
         
     | 
| 
      
 25 
     | 
    
         
            +
                    unless range.respond_to?(:first) and range.respond_to?(:last)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      fail ArgumentError, "Range or two element Array expected"
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                    start          = cast_key_in(range.first)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    include_start  = !options.fetch(:exclude_start, false)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    finish         = cast_key_in(range.last)
         
     | 
| 
      
 31 
     | 
    
         
            +
                    include_finish = !( range.respond_to?(:exclude_end?) ?
         
     | 
| 
      
 32 
     | 
    
         
            +
                                        range.exclude_end?               :
         
     | 
| 
      
 33 
     | 
    
         
            +
                                        options.fetch(:exclude_end, false) )
         
     | 
| 
      
 34 
     | 
    
         
            +
                  else
         
     | 
| 
      
 35 
     | 
    
         
            +
                    fail ArgumentError, "prefix not supported" if options[:prefix]
         
     | 
| 
      
 36 
     | 
    
         
            +
                    start          = cast_key_in(:min)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    include_start  = true
         
     | 
| 
      
 38 
     | 
    
         
            +
                    finish         = cast_key_in(:max)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    include_finish = true
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                  limit = options.fetch(:limit, -1)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  Utilities.temp_int do |count|
         
     | 
| 
      
 43 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 44 
     | 
    
         
            +
                      list  = lib.range(@db, start, finish, limit, count)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      array = list.get_array_of_uint64(0, count.get_int(0))
         
     | 
| 
      
 46 
     | 
    
         
            +
                      array.shift if array.first == start  and not include_start
         
     | 
| 
      
 47 
     | 
    
         
            +
                      array.pop   if array.last  == finish and not include_finish
         
     | 
| 
      
 48 
     | 
    
         
            +
                      array
         
     | 
| 
      
 49 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 50 
     | 
    
         
            +
                      Utilities.free(list) if list
         
     | 
| 
      
 51 
     | 
    
         
            +
                    end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                
         
     | 
| 
      
 55 
     | 
    
         
            +
                #################
         
     | 
| 
      
 56 
     | 
    
         
            +
                ### Iteration ###
         
     | 
| 
      
 57 
     | 
    
         
            +
                #################
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def each_key
         
     | 
| 
      
 60 
     | 
    
         
            +
                  try(:iterinit)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  loop do
         
     | 
| 
      
 62 
     | 
    
         
            +
                    return self unless key = try( :iternext,
         
     | 
| 
      
 63 
     | 
    
         
            +
                                                  :failure  => 0,
         
     | 
| 
      
 64 
     | 
    
         
            +
                                                  :no_error => {22 => nil} )
         
     | 
| 
      
 65 
     | 
    
         
            +
                    yield key
         
     | 
| 
      
 66 
     | 
    
         
            +
                  end
         
     | 
| 
      
 67 
     | 
    
         
            +
                end
         
     | 
| 
      
 68 
     | 
    
         
            +
                
         
     | 
| 
      
 69 
     | 
    
         
            +
                def each
         
     | 
| 
      
 70 
     | 
    
         
            +
                  each_key do |key|
         
     | 
| 
      
 71 
     | 
    
         
            +
                    yield [key, self[key]]
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
                alias_method :each_pair, :each
         
     | 
| 
      
 75 
     | 
    
         
            +
                
         
     | 
| 
      
 76 
     | 
    
         
            +
                #######
         
     | 
| 
      
 77 
     | 
    
         
            +
                private
         
     | 
| 
      
 78 
     | 
    
         
            +
                #######
         
     | 
| 
      
 79 
     | 
    
         
            +
                
         
     | 
| 
      
 80 
     | 
    
         
            +
                def tune(options)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  if options.values_at(:width, :limsiz).any?
         
     | 
| 
      
 82 
     | 
    
         
            +
                    optimize(options.merge(:tune => true))
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                end
         
     | 
| 
      
 85 
     | 
    
         
            +
                
         
     | 
| 
      
 86 
     | 
    
         
            +
                def cast_key_in(key)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  case key
         
     | 
| 
      
 88 
     | 
    
         
            +
                  when :min, :max, :prev, :next, "min", "max", "prev", "next"
         
     | 
| 
      
 89 
     | 
    
         
            +
                    C::IDS["FDBID#{key.to_s.upcase}".to_sym]
         
     | 
| 
      
 90 
     | 
    
         
            +
                  else
         
     | 
| 
      
 91 
     | 
    
         
            +
                    key.to_i
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
            end
         
     |