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 +4 -2
- data/README.rdoc +12 -12
- data/initializers/rdb.rb +2 -0
- data/lib/miyazaki_resistance.rb +17 -0
- data/lib/miyazaki_resistance/base.rb +31 -67
- data/lib/miyazaki_resistance/column.rb +89 -0
- data/lib/miyazaki_resistance/connection.rb +163 -0
- data/lib/miyazaki_resistance/miyazaki_logger.rb +11 -25
- data/lib/miyazaki_resistance/operation.rb +24 -0
- data/lib/miyazakiresistance.rb +1 -40
- metadata +5 -3
- data/lib/miyazaki_resistance/enhance.rb +0 -43
- data/lib/miyazaki_resistance/tokyo_connection.rb +0 -147
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/
|
10
|
-
lib/miyazaki_resistance/
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
@@ -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
|
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
|
-
|
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
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
-
|
162
|
-
|
163
|
-
|
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 :
|
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" ? :
|
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 = :
|
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 = :
|
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.
|
268
|
-
ret =
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
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.
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
11
|
+
class << self
|
12
12
|
def logger
|
13
|
-
|
13
|
+
@@logger || (logger = Logger.new(default_log_file_path))
|
14
14
|
end
|
15
15
|
|
16
16
|
def logger=(target)
|
17
|
-
|
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
|
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
|
data/lib/miyazakiresistance.rb
CHANGED
@@ -1,40 +1 @@
|
|
1
|
-
|
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.
|
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/
|
56
|
-
- lib/miyazaki_resistance/
|
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
|