tsukasaoishi-miyazakiresistance 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/Rakefile +1 -1
  2. data/lib/miyazakiresistance.rb +128 -49
  3. metadata +4 -4
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require File.dirname(__FILE__) + '/lib/miyazakiresistance'
4
4
  # Generate all the Rake tasks
5
5
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
6
  $hoe = Hoe.new('miyazakiresistance', MiyazakiResistance::VERSION) do |p|
7
- p.developer('FIXME full name', 'FIXME email')
7
+ p.developer('Tsukasa OISHI', 'tsukasa.oishi@gmail.com')
8
8
  p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
9
  p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
10
  p.rubyforge_name = p.name # TODO this is default value
@@ -3,15 +3,19 @@ $:.unshift(File.dirname(__FILE__)) unless
3
3
 
4
4
  require 'tokyotyrant'
5
5
  require 'timeout'
6
+ require 'logger'
6
7
 
7
8
  module MiyazakiResistance
8
- VERSION = '0.0.1'
9
+ VERSION = '0.0.2'
9
10
 
10
- class NewRecordError < StandardError; end
11
- class QueryError < StandardError; end
12
- class AllTimeoutORConnectionPoolEmpty < StandardError; end
11
+ class MiyazakiResistanceError < StandardError; end
12
+ class TokyoTyrantConnectError < MiyazakiResistanceError; end
13
+ class NewRecordError < MiyazakiResistanceError; end
14
+ class QueryError < MiyazakiResistanceError; end
15
+ class MasterDropError < MiyazakiResistanceError; end
16
+ class AllTimeoutORConnectionPoolEmpty < MiyazakiResistanceError; end
13
17
 
14
- module Connection
18
+ module TokyoConnection
15
19
  def self.included(base)
16
20
  base.extend ClassMethods
17
21
  base.__send__(:include, InstanceMethods)
@@ -23,12 +27,19 @@ module MiyazakiResistance
23
27
  attr_accessor :all_indexes
24
28
  attr_accessor :timeout_time
25
29
 
26
- def host_and_port(host, port, target = :write)
27
- self.connection_pool ||= {:read => [], :write => []}
30
+ def set_server(host, port, target = :readonly)
31
+ logger.debug "set_server host : #{host} port : #{port} target : #{target}"
32
+
33
+ self.connection_pool ||= {:read => [], :write => nil, :standby => nil}
28
34
  rdb = TokyoTyrant::RDBTBL.new
29
- return unless rdb.open(host, port)
35
+ unless rdb.open(host, port)
36
+ logger.error "TokyoTyrantConnectError host : #{host} port : #{port} target : #{target}"
37
+ raise TokyoTyrantConnectError
38
+ end
39
+
30
40
  self.connection_pool[:read] << rdb
31
- self.connection_pool[:write] << rdb if target == :write
41
+ self.connection_pool[:write] = rdb if target == :write
42
+ self.connection_pool[:standby] = rdb if target == :standby
32
43
  end
33
44
 
34
45
  def set_timeout(seconds)
@@ -36,39 +47,28 @@ module MiyazakiResistance
36
47
  end
37
48
 
38
49
  def set_column(name, type, index = :no_index)
39
- name = name.to_s
40
- self.__send__(:attr_accessor, name)
41
50
  self.all_indexes ||= []
42
51
  self.all_columns ||= {}
52
+ name = name.to_s
53
+ self.__send__(:attr_accessor, name)
43
54
  self.all_columns.update(name => type)
44
- if index == :index
45
- index_type =
46
- if [:integer, :datetime, :date].include?(type)
47
- TokyoTyrant::RDBTBL::ITDECIMAL
48
- elsif type == :string
49
- TokyoTyrant::RDBTBL::ITLEXICAL
50
- end
51
- self.all_indexes << name
52
- con = connection(:write)
53
- begin
54
- con.setindex(name, index_type)
55
- rescue TimeoutError
56
- remove_pool(con)
57
- retry
58
- end
59
- end
55
+
56
+ set_index(name, type) if index == :index
57
+ end
58
+
59
+ def read_connection
60
+ check_pool
61
+ self.connection_pool[:read].sort_by{rand}.first
60
62
  end
61
63
 
62
- def connection(target = :read)
63
- check_pool(target)
64
- self.connection_pool[target].sort_by{rand}.first
64
+ def write_connection
65
+ self.connection_pool[:write]
65
66
  end
66
67
 
67
68
  def remove_pool(rdb)
68
- [:read, :write].each do |target|
69
- self.connection_pool[target].delete_if{|pool| pool == rdb}
70
- check_pool(target)
71
- end
69
+ self.connection_pool[:read].delete_if{|pool| pool == rdb}
70
+ check_pool
71
+ fail_over if rdb == self.connection_pool[:write]
72
72
  end
73
73
 
74
74
  def kaeru_timeout(&block)
@@ -80,14 +80,54 @@ module MiyazakiResistance
80
80
 
81
81
  private
82
82
 
83
- def check_pool(target)
84
- raise AllTimeoutORConnectionPoolEmpty if self.connection_pool[target].empty?
83
+ def all_connections
84
+ [self.connection_pool[:read], self.connection_pool[:write], self.connection_pool[:standby]].flatten.compact.uniq
85
+ end
86
+
87
+ def check_pool
88
+ return if self.connection_pool[:read] && !self.connection_pool[:read].empty?
89
+ logger.error "AllTimeoutORConnectionPoolEmpty"
90
+ raise AllTimeoutORConnectionPoolEmpty
91
+ end
92
+
93
+ def fail_over
94
+ unless self.connection_pool[:standby]
95
+ logger.error "MasterDropError"
96
+ raise MasterDropError
97
+ end
98
+
99
+ logger.info "master server failover"
100
+ self.connection_pool[:write] = self.connection_pool[:standby]
101
+ self.connection_pool[:standby] = nil
102
+ end
103
+
104
+ def set_index(name, type)
105
+ index_type = case type
106
+ when :integer, :datetime, :date
107
+ TokyoTyrant::RDBTBL::ITDECIMAL
108
+ when :string
109
+ TokyoTyrant::RDBTBL::ITLEXICAL
110
+ end
111
+
112
+ self.all_indexes << name
113
+ all_connections.each do |con|
114
+ begin
115
+ con.setindex(name, index_type)
116
+ rescue TimeoutError
117
+ remove_pool(con)
118
+ retry
119
+ end
120
+ end
85
121
  end
86
122
  end
87
123
 
88
124
  module InstanceMethods
89
- def connection(target = :read)
90
- self.class.connection(target)
125
+ def read_connection
126
+ self.class.read_connection
127
+ end
128
+
129
+ def write_connection
130
+ self.class.write_connection
91
131
  end
92
132
 
93
133
  def remove_pool(rdb)
@@ -100,11 +140,40 @@ module MiyazakiResistance
100
140
  end
101
141
  end
102
142
 
143
+ module MiyazakiLogger
144
+ def self.included(base)
145
+ base.class_eval do
146
+ @@logger = nil
147
+ end
148
+ base.extend ClassMethods
149
+ base.__send__(:include, InstanceMethods)
150
+ end
151
+
152
+ module ClassMethods
153
+ def logger
154
+ @@logger ||= Logger.new("miyazakiresistance.log")
155
+ end
156
+
157
+ def logger=(target)
158
+ @@logger = target
159
+ end
160
+ end
161
+
162
+ module InstanceMethods
163
+ def logger
164
+ self.class.logger
165
+ end
166
+ end
167
+ end
168
+
103
169
  class Base
104
- include Connection
170
+ include TokyoConnection
171
+ include MiyazakiLogger
105
172
 
106
173
  OPERATIONS = {
107
174
  "=" => {:string => TokyoTyrant::RDBQRY::QCSTREQ, :integer => TokyoTyrant::RDBQRY::QCNUMEQ},
175
+ "!=" => {:string => ~TokyoTyrant::RDBQRY::QCSTREQ, :integer => ~TokyoTyrant::RDBQRY::QCNUMEQ},
176
+ "<>" => {:string => ~TokyoTyrant::RDBQRY::QCSTREQ, :integer => ~TokyoTyrant::RDBQRY::QCNUMEQ},
108
177
  "include" => {:string => TokyoTyrant::RDBQRY::QCSTRINC},
109
178
  "begin" => {:string => TokyoTyrant::RDBQRY::QCSTRBW},
110
179
  "end" => {:string => TokyoTyrant::RDBQRY::QCSTREW},
@@ -112,17 +181,19 @@ module MiyazakiResistance
112
181
  "anyinclude" => {:string => TokyoTyrant::RDBQRY::QCSTROR},
113
182
  "in" => {:string => TokyoTyrant::RDBQRY::QCSTROREQ, :integer => TokyoTyrant::RDBQRY::QCNUMOREQ},
114
183
  "=~" => {:string => TokyoTyrant::RDBQRY::QCSTRRX},
184
+ "!~" => {:string => ~TokyoTyrant::RDBQRY::QCSTRRX},
115
185
  ">" => {:integer => TokyoTyrant::RDBQRY::QCNUMGT},
116
186
  ">=" => {:integer => TokyoTyrant::RDBQRY::QCNUMGE},
117
187
  "<" => {:integer => TokyoTyrant::RDBQRY::QCNUMLT},
118
188
  "<=" => {:integer => TokyoTyrant::RDBQRY::QCNUMLE},
119
189
  "between" => {:integer => TokyoTyrant::RDBQRY::QCNUMBT}
120
190
  }
191
+ NOT_OPERATIONS = %w|include begin end allinclude anyinclude in between|
121
192
  DATE_TYPE = [:datetime, :date]
122
193
 
123
194
  attr_accessor :id
124
195
 
125
- def initialize(args)
196
+ def initialize(args = nil)
126
197
  args ||= {}
127
198
  self.id = nil
128
199
  args.each do |key, value|
@@ -146,12 +217,9 @@ module MiyazakiResistance
146
217
 
147
218
  def save
148
219
  time_column_check
149
- con = connection(:write)
220
+ con = write_connection
150
221
  self.id = kaeru_timeout{con.genuid.to_i} if new_record?
151
- kaeru_timeout do
152
- con.put(self.id, raw_attributes)
153
- self.class.all_indexes.each {|index| con.setindex(index, TokyoTyrant::RDBTBL::ITOPT)}
154
- end
222
+ kaeru_timeout {con.put(self.id, raw_attributes)}
155
223
  rescue TimeoutError
156
224
  remove_pool(con)
157
225
  retry
@@ -166,7 +234,7 @@ module MiyazakiResistance
166
234
 
167
235
  def destroy
168
236
  raise NewRecordError if new_record?
169
- con = connection(:write)
237
+ con = write_connection
170
238
  kaeru_timeout{con.out(self.id)}
171
239
  rescue TimeoutError
172
240
  remove_pool(con)
@@ -202,7 +270,7 @@ module MiyazakiResistance
202
270
  end
203
271
 
204
272
  def find_by_query(mode, args={})
205
- con = connection
273
+ con = read_connection
206
274
  query = TokyoTyrant::RDBQRY.new(con)
207
275
 
208
276
  limit = (mode == :first ? 1 : args[:limit])
@@ -224,7 +292,7 @@ module MiyazakiResistance
224
292
  end
225
293
 
226
294
  def count(args = {})
227
- con = connection
295
+ con = read_connection
228
296
  if args.empty?
229
297
  kaeru_timeout{con.rnum}
230
298
  else
@@ -282,7 +350,7 @@ module MiyazakiResistance
282
350
  def self.find_by_ids(targets)
283
351
  targets.map do |key|
284
352
  begin
285
- con = connection
353
+ con = read_connection
286
354
  data = kaeru_timeout{con.get(key)}
287
355
  inst = self.new(data)
288
356
  inst.id = key.to_i
@@ -318,7 +386,10 @@ module MiyazakiResistance
318
386
  param = conditions[1..-1]
319
387
 
320
388
  col, ope, exp, type = nil, nil, nil, nil
389
+ not_flag = false
321
390
  cond.split.each do |item|
391
+ next if %w|AND and|.include?(item)
392
+
322
393
  if self.all_columns.keys.include?(item)
323
394
  col = item
324
395
  type = self.all_columns[item]
@@ -330,6 +401,13 @@ module MiyazakiResistance
330
401
  work = type
331
402
  work = :integer if DATE_TYPE.include?(work)
332
403
  ope = OPERATIONS[item][work]
404
+ if not_flag
405
+ raise QueryError unless NOT_OPERATIONS.include?(item)
406
+ ope = ~ope
407
+ not_flag = false
408
+ end
409
+ elsif %w|NOT not|.include?(item)
410
+ not_flag = true
333
411
  else
334
412
  raise QueryError if col.nil? || type.nil? || ope.nil?
335
413
  exp = (item == "?" ? param.shift : item)
@@ -339,6 +417,7 @@ module MiyazakiResistance
339
417
  if col && type && ope && exp
340
418
  query.addcond(col, ope, exp.to_s)
341
419
  col, ope, exp, type = nil, nil, nil, nil
420
+ not_flag = false
342
421
  end
343
422
  end
344
423
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tsukasaoishi-miyazakiresistance
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
- - FIXME full name
7
+ - Tsukasa OISHI
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-21 00:00:00 -07:00
12
+ date: 2009-03-25 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -34,7 +34,7 @@ dependencies:
34
34
  version:
35
35
  description: MiyazakiResistance is a library like ActiveRecord to use Tokyo Tyrant.
36
36
  email:
37
- - FIXME email
37
+ - tsukasa.oishi@gmail.com
38
38
  executables: []
39
39
 
40
40
  extensions: []