miyazakiresistance 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
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