miyazakiresistance 0.1.5 → 0.1.6

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/Manifest.txt CHANGED
@@ -3,9 +3,11 @@ Manifest.txt
3
3
  README.rdoc
4
4
  Rakefile
5
5
  lib/miyazakiresistance.rb
6
+ lib/miyazaki_resistance.rb
6
7
  lib/miyazaki_resistance/base.rb
7
8
  lib/miyazaki_resistance/error.rb
8
9
  lib/miyazaki_resistance/miyazaki_logger.rb
9
- lib/miyazaki_resistance/tokyo_connection.rb
10
- lib/miyazaki_resistance/enhance.rb
10
+ lib/miyazaki_resistance/connection.rb
11
+ lib/miyazaki_resistance/column.rb
12
+ lib/miyazaki_resistance/operation.rb
11
13
  initializers/rdb.rb
data/README.rdoc CHANGED
@@ -12,13 +12,13 @@ MiyazakiResistance support Dual Master(Active/Standby). If Active server down, S
12
12
 
13
13
  require 'miyazakiresistance'
14
14
  class Example < MiyazakiResistance::Base
15
- set_server "localhost", 1975, :write
16
- set_server "slave", 1975, :standby
17
- set_timeout 1
18
- set_column :name, :string
19
- set_column :age, :integer
20
- set_column :birthday, :date
21
- set_column :created_at, :datetime
15
+ server :localhost, 1975, :write
16
+ server :slave_host, 1975, :standby
17
+ timeout 1
18
+ column :name, :string
19
+ column :age, :number
20
+ column :birthday, :date
21
+ column :created_at, :datetime
22
22
  end
23
23
 
24
24
  work = Example.new
@@ -48,11 +48,11 @@ MiyazakiResistance support Dual Master(Active/Standby). If Active server down, S
48
48
  require 'miyazakiresistance'
49
49
  class Example < MiyazakiResistance::Base
50
50
  server_config Rails.env, "log/miyazakiresistance.yml"
51
- set_timeout 60
52
- set_column :name, :string
53
- set_column :age, :integer
54
- set_column :birthday, :date
55
- set_column :created_at, :datetime
51
+ timeout 60
52
+ column :name, :string
53
+ column :age, :integer
54
+ column :birthday, :date
55
+ column :created_at, :datetime
56
56
  end
57
57
 
58
58
  'in log/miyazakiresistance.log'
data/initializers/rdb.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'tokyotyrant'
2
+
1
3
  module TokyoTyrant
2
4
  class RDB
3
5
  attr_accessor :host, :port, :open_flag
@@ -0,0 +1,17 @@
1
+ Dir.glob("#{File.join(File.dirname(__FILE__), "../initializers")}/*.rb").each{|path| require path}
2
+
3
+ module MiyazakiResistance
4
+ VERSION = [0, 1, 6]
5
+
6
+ def self.version
7
+ VERSION * "."
8
+ end
9
+ end
10
+ MR = MiyazakiResistance
11
+
12
+ require "miyazaki_resistance/column"
13
+ require "miyazaki_resistance/operation"
14
+ require "miyazaki_resistance/connection"
15
+ require "miyazaki_resistance/base"
16
+ require "miyazaki_resistance/miyazaki_logger"
17
+ require "miyazaki_resistance/error"
@@ -3,30 +3,8 @@ module MiyazakiResistance
3
3
  attr_accessor :id
4
4
 
5
5
  def initialize(args = nil)
6
- args ||= {}
7
6
  self.id = nil
8
- args.each do |key, value|
9
- if key.is_a?(String) && key.empty?
10
- key = :id
11
- value = value.to_i
12
- else
13
- case self.class.all_columns[key.to_s]
14
- when :integer
15
- value = value.to_i
16
- when :string
17
- value = value.to_s
18
- when :datetime
19
- value = Time.at(value.to_i) unless value.is_a?(Time)
20
- when :date
21
- unless value.is_a?(Date)
22
- time = Time.at(value.to_i)
23
- value = Date.new(time.year, time.month, time.day)
24
- end
25
- end
26
- end
27
-
28
- self.__send__("#{key}=", value)
29
- end
7
+ set_args(args || {})
30
8
  end
31
9
 
32
10
  def save
@@ -55,16 +33,6 @@ module MiyazakiResistance
55
33
  retry
56
34
  end
57
35
 
58
- def attributes
59
- hash = {}
60
- self.class.all_columns.keys.each{|key| hash.update(key => self.__send__(key))}
61
- hash
62
- end
63
-
64
- def attributes=(args)
65
- args.each {|key, value| self.__send__("#{key}=", value)}
66
- end
67
-
68
36
  def new_record?
69
37
  self.id.nil?
70
38
  end
@@ -144,37 +112,32 @@ module MiyazakiResistance
144
112
  def create(args)
145
113
  self.new(args).save
146
114
  end
147
- end
148
115
 
149
- private
116
+ def method_missing(name, *arguments, &block)
117
+ if match = finder_attribute_names(name)
118
+ finder = match[:finder]
119
+ conditions = match[:cols].map{|col| "#{col} = ?"}.join(" ")
150
120
 
151
- def raw_attributes
152
- hash = {}
153
- self.class.all_columns.each do |col, type|
154
- value = self.__send__(col)
155
- value = self.class.plastic_data(value, type)
156
- hash.update(col.to_s => value)
157
- end
158
- hash
159
- end
121
+ self.class_eval %Q|
122
+ def self.#{name}(*args)
123
+ options = args.last.is_a?(::Hash) ? pop : {}
124
+ options.update(:conditions => ["#{conditions}", args].flatten)
125
+ self.find(:#{finder}, options)
126
+ end
127
+ |
160
128
 
161
- def time_column_check
162
- time_columns = ["updated"]
163
- time_columns << "created" if new_record?
164
- time_columns.each do |col|
165
- %w|at on|.each do |type|
166
- if self.class.all_columns.keys.include?("#{col}_#{type}")
167
- now = Time.now
168
- now = Date.new(now.year, now.month, now.day) if type == "on"
169
- self.__send__("#{col}_#{type}=", now) if self.__send__("#{col}_#{type}").nil? || col == "updated"
170
- end
129
+ __send__(name, *arguments)
130
+ else
131
+ super
171
132
  end
172
133
  end
173
134
  end
174
135
 
136
+ private
137
+
175
138
  def self.type_upcase(type)
176
139
  case type
177
- when :integer, :datetime, :date
140
+ when :number, :datetime, :date
178
141
  "NUM"
179
142
  when :string
180
143
  "STR"
@@ -205,7 +168,7 @@ module MiyazakiResistance
205
168
  if order
206
169
  target, order_type = order.split
207
170
  if target == "id" || self.all_columns.keys.include?(target)
208
- type = (target == "id" ? :integer : self.all_columns[target])
171
+ type = (target == "id" ? :number : self.all_columns[target])
209
172
  target = "" if target == "id"
210
173
  order_type ||= "asc"
211
174
  eval(%Q|query.setorder(target, TokyoTyrant::RDBQRY::QO#{type_upcase(type)}#{order_type.upcase})|)
@@ -230,11 +193,11 @@ module MiyazakiResistance
230
193
  type = self.all_columns[item]
231
194
  elsif item == "id"
232
195
  col = ""
233
- type = :integer
196
+ type = :number
234
197
  elsif OPERATIONS.keys.include?(item)
235
198
  raise QueryError if col.nil? || type.nil?
236
199
  work = type
237
- work = :integer if DATE_TYPE.include?(work)
200
+ work = :number if DATE_TYPE.include?(work)
238
201
  ope = OPERATIONS[item][work]
239
202
  if not_flag
240
203
  raise QueryError unless NOT_OPERATIONS.include?(item)
@@ -264,16 +227,17 @@ module MiyazakiResistance
264
227
  query
265
228
  end
266
229
 
267
- def self.plastic_data(value, type)
268
- ret = case type
269
- when :datetime
270
- value.to_i
271
- when :date
272
- Time.local(value.year, value.month, value.day).to_i
273
- else
274
- value
230
+ def self.finder_attribute_names(name)
231
+ ret = {:finder => :first, :cols => nil}
232
+ if name.to_s =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/
233
+ ret[:finder] = :all if $1 == "all_by"
234
+ if cols = $2
235
+ cols = cols.split("_and_")
236
+ all_cols = self.all_columns.keys
237
+ ret[:cols] = cols if cols.all?{|col| all_cols.include?(col)}
238
+ end
275
239
  end
276
- ret.to_s
240
+ (ret[:cols].nil? || ret[:cols].empty?) ? nil : ret
277
241
  end
278
242
  end
279
243
  end
@@ -0,0 +1,89 @@
1
+ module MiyazakiResistance
2
+ class Base
3
+ class << self
4
+ attr_accessor :all_columns
5
+
6
+ def column(name, type, index = :no_index)
7
+ self.all_columns ||= {}
8
+ name = name.to_s
9
+ self.__send__(:attr_accessor, name)
10
+ type = :number if type.to_s == "integer"
11
+ self.all_columns.update(name => type)
12
+ end
13
+ alias :set_column :column
14
+
15
+ def plastic_data(value, type)
16
+ ret = case type
17
+ when :datetime
18
+ value ? value.to_i : nil
19
+ when :date
20
+ value ? Time.local(value.year, value.month, value.day).to_i : nil
21
+ else
22
+ value
23
+ end
24
+ ret.to_s
25
+ end
26
+ end
27
+
28
+ def attributes
29
+ self.class.all_columns.keys.inject({}) {|hash, key| hash.merge(key => self.__send__(key))}
30
+ end
31
+
32
+ def attributes=(args)
33
+ args.each {|key, value| self.__send__("#{key}=", value)}
34
+ end
35
+
36
+ private
37
+
38
+ def raw_attributes
39
+ hash = {}
40
+ self.class.all_columns.each do |col, type|
41
+ next unless value = self.__send__(col)
42
+ value = self.class.plastic_data(value, type)
43
+ hash.update(col.to_s => value)
44
+ end
45
+ hash
46
+ end
47
+
48
+ def time_column_check
49
+ time_columns = ["updated"]
50
+ time_columns << "created" if new_record?
51
+ time_columns.each do |col|
52
+ %w|at on|.each do |type|
53
+ if self.class.all_columns.keys.include?("#{col}_#{type}")
54
+ now = Time.now
55
+ now = Date.new(now.year, now.month, now.day) if type == "on"
56
+ self.__send__("#{col}_#{type}=", now) if self.__send__("#{col}_#{type}").nil? || col == "updated"
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ def set_args(args)
63
+ args.each do |key, value|
64
+ if key.is_a?(String) && key.empty?
65
+ key, = :id
66
+ value = value.to_i if value
67
+ else
68
+ case self.class.all_columns[key.to_s]
69
+ when :number
70
+ value = (value =~ /\./) ? value.to_f : value.to_i if value
71
+ when :string
72
+ value = value.to_s if value
73
+ when :datetime
74
+ value = Time.at(value.to_i) if value && !value.is_a?(Time)
75
+ when :date
76
+ if value && !value.is_a?(Date)
77
+ time = Time.at(value.to_i)
78
+ value = Date.new(time.year, time.month, time.day)
79
+ end
80
+ else
81
+ next
82
+ end
83
+ end
84
+
85
+ self.__send__("#{key}=", value)
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,163 @@
1
+ require 'tokyotyrant'
2
+ require 'timeout'
3
+ require 'yaml'
4
+
5
+ module MiyazakiResistance
6
+ class Base
7
+ @@connection_manager = {}
8
+
9
+ class <<self
10
+ %w|server_config server timeout remove_pool|.each do |method|
11
+ class_eval %Q|
12
+ def #{method}(*args)
13
+ connection_or_create.#{method}(*args)
14
+ end
15
+ |
16
+ end
17
+ alias :set_server :server
18
+ alias :set_timeout :timeout
19
+
20
+ %w|read write|.each do |role|
21
+ class_eval %Q|
22
+ def #{role}_connection
23
+ con = connection
24
+ con ? con.#{role}_connection : nil
25
+ end
26
+ |
27
+ end
28
+
29
+ def connection
30
+ @@connection_manager[self]
31
+ end
32
+
33
+ def connection_or_create
34
+ @@connection_manager[self] ||= MR::Connection.new
35
+ end
36
+
37
+ def kaeru_timeout(&block)
38
+ con = connection
39
+ con.kaeru_timeout(&block)
40
+ end
41
+ end
42
+
43
+ def read_connection
44
+ self.class.read_connection
45
+ end
46
+
47
+ def write_connection
48
+ self.class.write_connection
49
+ end
50
+
51
+ def remove_pool(con)
52
+ self.class.remove_pool(con)
53
+ end
54
+
55
+ def kaeru_timeout(&block)
56
+ self.class.kaeru_timeout(&block)
57
+ end
58
+ end
59
+
60
+ class Connection
61
+ DEFAULT = {:timeout => 5, :config => "miyazakiresistance.yml", :port => 1978, :role => :readonly}
62
+
63
+ attr_accessor :connection_pool
64
+ attr_accessor :timeout_time
65
+
66
+ def server_config(env, file = DEFAULT[:config])
67
+ conf = YAML.load_file(file)
68
+ if config = conf[env.to_s]
69
+ config["set_server"].each do |work|
70
+ server(work["server"], work["port"], work["role"])
71
+ end
72
+ else
73
+ MR::MiyazakiLogger.fatal "specified environment(#{env}) is not found in conig file(#{file})"
74
+ end
75
+ rescue Errno::ENOENT => e
76
+ MR::MiyazakiLogger.fatal "config file is not found : #{file}"
77
+ end
78
+
79
+ def server(host, port = DEFAULT[:port], role = DEFAULT[:role])
80
+ self.connection_pool ||= {:read => [], :write => nil, :standby => nil}
81
+ rdb = TokyoTyrant::RDBTBL.new
82
+ MR::MiyazakiLogger.info "set server host : #{host} port : #{port} role : #{role}"
83
+
84
+ rdb.set_server(host.to_s, port)
85
+
86
+ if role.to_sym == :standby
87
+ self.connection_pool[:standby] = rdb
88
+ else
89
+ self.connection_pool[:read] << rdb
90
+ self.connection_pool[:write] = rdb if role.to_sym == :write
91
+ end
92
+ end
93
+
94
+ def timeout(seconds)
95
+ self.timeout_time = seconds.to_i
96
+ end
97
+
98
+ def connection(con)
99
+ unless con.open?
100
+ unless con.open
101
+ MR::MiyazakiLogger.fatal "TokyoTyrantConnectError host : #{con.host} port : #{con.port}"
102
+ raise MiyazakiResistance::TokyoTyrantConnectError
103
+ end
104
+ end
105
+ con
106
+ end
107
+
108
+ def read_connection
109
+ check_pool
110
+ connection(self.connection_pool[:read].sort_by{rand}.first)
111
+ end
112
+
113
+ def write_connection
114
+ connection(self.connection_pool[:write])
115
+ end
116
+
117
+ def remove_pool(rdb)
118
+ self.connection_pool[:read].delete_if{|pool| pool == rdb}
119
+
120
+ host, port = rdb.host, rdb.port
121
+ new_rdb = TokyoTyrant::RDBTBL.new
122
+ if new_rdb.open(host, port)
123
+ self.connection_pool[:read] << new_rdb
124
+ self.connection_pool[:write] = new_rdb if rdb == self.connection_pool[:write]
125
+ else
126
+ MR::MiyazakiLogger.fatal "remove pool : host #{host} port : #{port}"
127
+ fail_over if rdb == self.connection_pool[:write]
128
+ end
129
+ rdb.close
130
+ end
131
+
132
+ def kaeru_timeout(&block)
133
+ ret = nil
134
+ thread = Thread.new{ret = yield}
135
+ raise TimeoutError, "tokyo tyrant server response error" unless thread.join(self.timeout_time || DEFAULT[:timeout])
136
+ ret
137
+ end
138
+
139
+ private
140
+
141
+ def all_connections
142
+ [self.connection_pool[:read], self.connection_pool[:write], self.connection_pool[:standby]].flatten.compact.uniq
143
+ end
144
+
145
+ def check_pool
146
+ return if self.connection_pool[:read] && !self.connection_pool[:read].empty?
147
+ MR::MiyazakiLogger.fatal "AllTimeoutORConnectionPoolEmpty"
148
+ raise MiyazakiResistance::AllTimeoutORConnectionPoolEmpty
149
+ end
150
+
151
+ def fail_over
152
+ unless self.connection_pool[:standby]
153
+ MR::MiyazakiLogger.fatal "MasterDropError"
154
+ raise MiyazakiResistance::MasterDropError
155
+ end
156
+
157
+ MR::MiyazakiLogger.fatal "master server failover"
158
+ self.connection_pool[:write] = self.connection_pool[:standby]
159
+ self.connection_pool[:read] << self.connection_pool[:standby]
160
+ self.connection_pool[:standby] = nil
161
+ end
162
+ end
163
+ end
@@ -1,25 +1,25 @@
1
+ require 'logger'
2
+
1
3
  module MiyazakiResistance
2
- module MiyazakiLogger
3
- def self.included(base)
4
- base.class_eval do
5
- @@logger = nil
6
- end
7
- base.extend ClassMethods
8
- base.__send__(:include, InstanceMethods)
4
+ class MiyazakiLogger
5
+ @@logger = nil
6
+
7
+ def initialize(file)
8
+ @file = file
9
9
  end
10
10
 
11
- module ClassMethods
11
+ class << self
12
12
  def logger
13
- class_variable_get("@@logger") || (logger = Logger.new(default_log_file_path))
13
+ @@logger || (logger = Logger.new(default_log_file_path))
14
14
  end
15
15
 
16
16
  def logger=(target)
17
- class_variable_set("@@logger", target)
17
+ @@logger = target
18
18
  end
19
19
 
20
20
  %w|fatal error warn info debug|.each do|level|
21
21
  self.class_eval %Q|
22
- def logger_#{level}(str)
22
+ def #{level}(str)
23
23
  put_log(str, "#{level}")
24
24
  end
25
25
  |
@@ -39,19 +39,5 @@ module MiyazakiResistance
39
39
  File.directory?("log") ? "log/miyazakiresistance.log" : "miyazakiresistance.log"
40
40
  end
41
41
  end
42
-
43
- module InstanceMethods
44
- def logger
45
- self.class.logger
46
- end
47
-
48
- %w|fatal error warn info debug|.each do|level|
49
- self.class_eval %Q|
50
- def logger_#{level}(str)
51
- self.class.logger_#{level}g(str)
52
- end
53
- |
54
- end
55
- end
56
42
  end
57
43
  end
@@ -0,0 +1,24 @@
1
+ module MiyazakiResistance
2
+ class Base
3
+ OPERATIONS = {
4
+ "=" => {:string => TokyoTyrant::RDBQRY::QCSTREQ, :number => TokyoTyrant::RDBQRY::QCNUMEQ},
5
+ "!=" => {:string => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCSTREQ, :number => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCNUMEQ},
6
+ "<>" => {:string => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCSTREQ, :number => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCNUMEQ},
7
+ "include" => {:string => TokyoTyrant::RDBQRY::QCSTRINC},
8
+ "begin" => {:string => TokyoTyrant::RDBQRY::QCSTRBW},
9
+ "end" => {:string => TokyoTyrant::RDBQRY::QCSTREW},
10
+ "allinclude" => {:string => TokyoTyrant::RDBQRY::QCSTRAND},
11
+ "anyinclude" => {:string => TokyoTyrant::RDBQRY::QCSTROR},
12
+ "in" => {:string => TokyoTyrant::RDBQRY::QCSTROREQ, :number => TokyoTyrant::RDBQRY::QCNUMOREQ},
13
+ "=~" => {:string => TokyoTyrant::RDBQRY::QCSTRRX},
14
+ "!~" => {:string => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCSTRRX},
15
+ ">" => {:number => TokyoTyrant::RDBQRY::QCNUMGT},
16
+ ">=" => {:number => TokyoTyrant::RDBQRY::QCNUMGE},
17
+ "<" => {:number => TokyoTyrant::RDBQRY::QCNUMLT},
18
+ "<=" => {:number => TokyoTyrant::RDBQRY::QCNUMLE},
19
+ "between" => {:number => TokyoTyrant::RDBQRY::QCNUMBT}
20
+ }
21
+ NOT_OPERATIONS = %w|include begin end allinclude anyinclude in between|
22
+ DATE_TYPE = [:datetime, :date]
23
+ end
24
+ end
@@ -1,40 +1 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
- require 'logger'
5
- require 'timeout'
6
- require 'tokyotyrant'
7
-
8
- Dir.glob("#{File.join(File.dirname(__FILE__), "../initializers")}/*.rb").each{|path| require path}
9
- Dir.glob("#{File.join(File.dirname(__FILE__), "miyazaki_resistance")}/*.rb").each{|path| require path}
10
-
11
- module MiyazakiResistance
12
- VERSION = '0.1.5'
13
- end
14
-
15
- MiyazakiResistance::Base.class_eval do
16
- include MiyazakiResistance::TokyoConnection
17
- include MiyazakiResistance::Enhance
18
- include MiyazakiResistance::MiyazakiLogger
19
-
20
- OPERATIONS = {
21
- "=" => {:string => TokyoTyrant::RDBQRY::QCSTREQ, :integer => TokyoTyrant::RDBQRY::QCNUMEQ},
22
- "!=" => {:string => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCSTREQ, :integer => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCNUMEQ},
23
- "<>" => {:string => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCSTREQ, :integer => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCNUMEQ},
24
- "include" => {:string => TokyoTyrant::RDBQRY::QCSTRINC},
25
- "begin" => {:string => TokyoTyrant::RDBQRY::QCSTRBW},
26
- "end" => {:string => TokyoTyrant::RDBQRY::QCSTREW},
27
- "allinclude" => {:string => TokyoTyrant::RDBQRY::QCSTRAND},
28
- "anyinclude" => {:string => TokyoTyrant::RDBQRY::QCSTROR},
29
- "in" => {:string => TokyoTyrant::RDBQRY::QCSTROREQ, :integer => TokyoTyrant::RDBQRY::QCNUMOREQ},
30
- "=~" => {:string => TokyoTyrant::RDBQRY::QCSTRRX},
31
- "!~" => {:string => TokyoTyrant::RDBQRY::QCNEGATE | TokyoTyrant::RDBQRY::QCSTRRX},
32
- ">" => {:integer => TokyoTyrant::RDBQRY::QCNUMGT},
33
- ">=" => {:integer => TokyoTyrant::RDBQRY::QCNUMGE},
34
- "<" => {:integer => TokyoTyrant::RDBQRY::QCNUMLT},
35
- "<=" => {:integer => TokyoTyrant::RDBQRY::QCNUMLE},
36
- "between" => {:integer => TokyoTyrant::RDBQRY::QCNUMBT}
37
- }
38
- NOT_OPERATIONS = %w|include begin end allinclude anyinclude in between|
39
- DATE_TYPE = [:datetime, :date]
40
- end
1
+ require 'miyazaki_resistance'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miyazakiresistance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tsukasa OISHI
@@ -49,11 +49,13 @@ files:
49
49
  - README.rdoc
50
50
  - Rakefile
51
51
  - lib/miyazakiresistance.rb
52
+ - lib/miyazaki_resistance.rb
52
53
  - lib/miyazaki_resistance/base.rb
53
54
  - lib/miyazaki_resistance/error.rb
54
55
  - lib/miyazaki_resistance/miyazaki_logger.rb
55
- - lib/miyazaki_resistance/tokyo_connection.rb
56
- - lib/miyazaki_resistance/enhance.rb
56
+ - lib/miyazaki_resistance/connection.rb
57
+ - lib/miyazaki_resistance/column.rb
58
+ - lib/miyazaki_resistance/operation.rb
57
59
  - initializers/rdb.rb
58
60
  has_rdoc: true
59
61
  homepage: http://www.kaeruspoon.net/keywords/MiyazakiResistance
@@ -1,43 +0,0 @@
1
- module MiyazakiResistance
2
- module Enhance
3
- def self.included(base)
4
- base.extend ClassMethods
5
- end
6
-
7
- module ClassMethods
8
- def method_missing(name, *arguments, &block)
9
- if match = finder_attribute_names(name)
10
- finder = match[:finder]
11
- conditions = match[:cols].map{|col| "#{col} = ?"}.join(" ")
12
-
13
- self.class_eval %Q|
14
- def self.#{name}(*args)
15
- options = args.last.is_a?(::Hash) ? pop : {}
16
- options.update(:conditions => ["#{conditions}", args].flatten)
17
- self.find(:#{finder}, options)
18
- end
19
- |
20
-
21
- __send__(name, *arguments)
22
- else
23
- super
24
- end
25
- end
26
-
27
- private
28
-
29
- def finder_attribute_names(name)
30
- ret = {:finder => :first, :cols => nil}
31
- if name.to_s =~ /^find_(all_by|by)_([_a-zA-Z]\w*)$/
32
- ret[:finder] = :all if $1 == "all_by"
33
- if cols = $2
34
- cols = cols.split("_and_")
35
- all_cols = self.all_columns.keys
36
- ret[:cols] = cols if cols.all?{|col| all_cols.include?(col)}
37
- end
38
- end
39
- (ret[:cols].nil? || ret[:cols].empty?) ? nil : ret
40
- end
41
- end
42
- end
43
- end
@@ -1,147 +0,0 @@
1
- require 'yaml'
2
- module MiyazakiResistance
3
- module TokyoConnection
4
- def self.included(base)
5
- base.extend ClassMethods
6
- base.__send__(:include, InstanceMethods)
7
- end
8
-
9
- module ClassMethods
10
- attr_accessor :connection_pool
11
- attr_accessor :all_columns
12
- attr_accessor :timeout_time
13
-
14
- DEFAULT = {
15
- :timeout => 5,
16
- :config => "miyazakiresistance.yml",
17
- :port => 1978,
18
- :role => :readonly
19
- }
20
-
21
- def server_config(env, file = DEFAULT[:config])
22
- env = env.to_s
23
- conf = YAML.load_file(file)
24
-
25
- if (config = conf[env]).nil?
26
- logger_fatal "specified environment(#{env}) is not found in conig file(#{file})"
27
- return
28
- end
29
-
30
- config["set_server"].each do |work|
31
- set_server work["server"], work["port"], work["role"]
32
- end
33
- rescue Errno::ENOENT => e
34
- logger_fatal "config file is not found : #{file}"
35
- end
36
-
37
- def set_server(host, port = DEFAULT[:port], role = DEFAULT[:role])
38
- self.connection_pool ||= {:read => [], :write => nil, :standby => nil}
39
- rdb = TokyoTyrant::RDBTBL.new
40
- logger_info "set server host : #{host} port : #{port} role : #{role}"
41
-
42
- rdb.set_server(host.to_s, port)
43
-
44
- if role.to_sym == :standby
45
- self.connection_pool[:standby] = rdb
46
- else
47
- self.connection_pool[:read] << rdb
48
- self.connection_pool[:write] = rdb if role.to_sym == :write
49
- end
50
- end
51
-
52
- def set_timeout(seconds)
53
- self.timeout_time = seconds.to_i
54
- end
55
-
56
- def set_column(name, type, index = :no_index)
57
- self.all_columns ||= {}
58
- name = name.to_s
59
- self.__send__(:attr_accessor, name)
60
- self.all_columns.update(name => type)
61
- end
62
-
63
- def connection(con)
64
- unless con.open?
65
- unless con.open
66
- logger_fatal "TokyoTyrantConnectError host : #{con.host} port : #{con.port}"
67
- raise TokyoTyrantConnectError
68
- end
69
- end
70
- con
71
- end
72
-
73
- def read_connection
74
- check_pool
75
- connection(self.connection_pool[:read].sort_by{rand}.first)
76
- end
77
-
78
- def write_connection
79
- connection(self.connection_pool[:write])
80
- end
81
-
82
- def remove_pool(rdb)
83
- self.connection_pool[:read].delete_if{|pool| pool == rdb}
84
-
85
- host, port = rdb.host, rdb.port
86
- new_rdb = TokyoTyrant::RDBTBL.new
87
- if new_rdb.open(host, port)
88
- self.connection_pool[:read] << new_rdb
89
- self.connection_pool[:write] = new_rdb if rdb == self.connection_pool[:write]
90
- else
91
- logger_fatal "remove pool : host #{host} port : #{port}"
92
- fail_over if rdb == self.connection_pool[:write]
93
- end
94
- rdb.close
95
- end
96
-
97
- def kaeru_timeout(&block)
98
- ret = nil
99
- thread = Thread.new{ret = yield}
100
- raise TimeoutError, "tokyo tyrant server response error" unless thread.join(self.timeout_time || DEFAULT[:timeout])
101
- ret
102
- end
103
-
104
- private
105
-
106
- def all_connections
107
- [self.connection_pool[:read], self.connection_pool[:write], self.connection_pool[:standby]].flatten.compact.uniq
108
- end
109
-
110
- def check_pool
111
- return if self.connection_pool[:read] && !self.connection_pool[:read].empty?
112
- logger_fatal "AllTimeoutORConnectionPoolEmpty"
113
- raise AllTimeoutORConnectionPoolEmpty
114
- end
115
-
116
- def fail_over
117
- unless self.connection_pool[:standby]
118
- logger_fatal "MasterDropError"
119
- raise MasterDropError
120
- end
121
-
122
- logger_fatal "master server failover"
123
- self.connection_pool[:write] = self.connection_pool[:standby]
124
- self.connection_pool[:read] << self.connection_pool[:standby]
125
- self.connection_pool[:standby] = nil
126
- end
127
- end
128
-
129
- module InstanceMethods
130
- def read_connection
131
- self.class.read_connection
132
- end
133
-
134
- def write_connection
135
- self.class.write_connection
136
- end
137
-
138
- def remove_pool(rdb)
139
- self.class.remove_pool(rdb)
140
- end
141
-
142
- def kaeru_timeout(&block)
143
- self.class.kaeru_timeout(&block)
144
- end
145
- end
146
- end
147
- end