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 +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
|