higgs 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,14 @@
1
1
  # = transactional storage core
2
2
  #
3
3
  # Author:: $Author: toki $
4
- # Date:: $Date: 2007-11-11 11:07:25 +0900 (Sun, 11 Nov 2007) $
5
- # Revision:: $Revision: 681 $
4
+ # Date:: $Date: 2008-01-14 00:55:53 +0900 (Mon, 14 Jan 2008) $
5
+ # Revision:: $Revision: 742 $
6
6
  #
7
7
  # == license
8
8
  # :include:LICENSE
9
9
  #
10
10
 
11
11
  require 'digest'
12
- require 'forwardable'
13
12
  require 'higgs/block'
14
13
  require 'higgs/cache'
15
14
  require 'higgs/flock'
@@ -24,9 +23,8 @@ module Higgs
24
23
  # = transactional storage core
25
24
  class Storage
26
25
  # for ident(1)
27
- CVS_ID = '$Id: storage.rb 681 2007-11-11 02:07:25Z toki $'
26
+ CVS_ID = '$Id: storage.rb 742 2008-01-13 15:55:53Z toki $'
28
27
 
29
- extend Forwardable
30
28
  include Exceptions
31
29
 
32
30
  class Error < HiggsError
@@ -193,6 +191,9 @@ module Higgs
193
191
  @panic = false
194
192
  @shutdown = false
195
193
 
194
+ @cnum_lock = Mutex.new
195
+ @saved_change_number = nil
196
+
196
197
  init_options(options)
197
198
 
198
199
  init_completed = false
@@ -591,6 +592,7 @@ module Higgs
591
592
  eoa = @index.eoa
592
593
 
593
594
  begin
595
+ @cnum_lock.synchronize{ @saved_change_number = @index.change_number }
594
596
  @index.succ!
595
597
  @logger.debug("index succ: #{@index.change_number}") if @logger.debug?
596
598
  commit_log << { :ope => :succ, :cnum => @index.change_number }
@@ -770,6 +772,7 @@ module Higgs
770
772
  @logger.error("panic: failed to commit.")
771
773
  @logger.error($!) if $!
772
774
  end
775
+ @cnum_lock.synchronize{ @saved_change_number = nil }
773
776
  end
774
777
 
775
778
  @logger.debug("completed raw_write_and_commit.") if @logger.debug?
@@ -1107,12 +1110,13 @@ module Higgs
1107
1110
  value
1108
1111
  end
1109
1112
 
1110
- def string_only(key)
1111
- properties = fetch_properties(key) or raise IndexError, "not exist properties at key: #{key}"
1112
- properties['system_properties']['string_only']
1113
+ def identity(key)
1114
+ @index.identity(key)
1113
1115
  end
1114
1116
 
1115
- def_delegator :@index, :identity
1117
+ def change_number
1118
+ @cnum_lock.synchronize{ @saved_change_number || @index.change_number }
1119
+ end
1116
1120
 
1117
1121
  def data_change_number(key)
1118
1122
  i = @index[key] and i[:d][:cnum] || -1
@@ -1133,6 +1137,12 @@ module Higgs
1133
1137
  @index.key? key
1134
1138
  end
1135
1139
 
1140
+ def keys(order_by_pos=false)
1141
+ keys = @index.keys
1142
+ keys.sort!{|a, b| @index[a][:d][:pos] <=> @index[b][:d][:pos] } if order_by_pos
1143
+ keys
1144
+ end
1145
+
1136
1146
  def each_key
1137
1147
  check_read
1138
1148
  @index.each_key do |key|
@@ -1152,19 +1162,11 @@ module Higgs
1152
1162
 
1153
1163
  def verify(out=nil, verbose_level=1)
1154
1164
  check_read
1155
-
1156
- keys = @index.keys
1157
- keys.sort!{|a, b|
1158
- @index[a][:d][:pos] <=> @index[b][:d][:pos]
1159
- }
1160
-
1161
- for key in keys
1165
+ for key in keys(true)
1162
1166
  if (out && verbose_level >= 1) then
1163
1167
  out << "check #{key}\n"
1164
1168
  end
1165
-
1166
1169
  data = fetch(key)
1167
-
1168
1170
  if (out && verbose_level >= 2) then
1169
1171
  out << " #{data.length} bytes\n"
1170
1172
  properties = fetch_properties(key) or raise PanicError, "not exist properties at key: #{key}"
@@ -1174,7 +1176,6 @@ module Higgs
1174
1176
  end
1175
1177
  end
1176
1178
  end
1177
-
1178
1179
  nil
1179
1180
  end
1180
1181
 
@@ -1,8 +1,8 @@
1
1
  # = multi-thread utilities
2
2
  #
3
3
  # Author:: $Author: toki $
4
- # Date:: $Date: 2007-11-14 01:42:21 +0900 (Wed, 14 Nov 2007) $
5
- # Revision:: $Revision: 686 $
4
+ # Date:: $Date: 2008-01-14 00:55:53 +0900 (Mon, 14 Jan 2008) $
5
+ # Revision:: $Revision: 742 $
6
6
  #
7
7
  # == license
8
8
  # :include:LICENSE
@@ -15,7 +15,7 @@ require 'thread'
15
15
  module Higgs
16
16
  class Latch
17
17
  # for ident(1)
18
- CVS_ID = '$Id: thread.rb 686 2007-11-13 16:42:21Z toki $'
18
+ CVS_ID = '$Id: thread.rb 742 2008-01-13 15:55:53Z toki $'
19
19
 
20
20
  def initialize
21
21
  @lock = Mutex.new
@@ -43,7 +43,7 @@ module Higgs
43
43
 
44
44
  class CountDownLatch
45
45
  # for ident(1)
46
- CVS_ID = '$Id: thread.rb 686 2007-11-13 16:42:21Z toki $'
46
+ CVS_ID = '$Id: thread.rb 742 2008-01-13 15:55:53Z toki $'
47
47
 
48
48
  def initialize(count)
49
49
  @count = count
@@ -55,7 +55,7 @@ module Higgs
55
55
  @lock.synchronize{
56
56
  if (@count > 0) then
57
57
  @count -= 1
58
- @cond.broadcast
58
+ @cond.broadcast if (@count == 0)
59
59
  end
60
60
  }
61
61
  nil
@@ -73,7 +73,7 @@ module Higgs
73
73
 
74
74
  class Barrier
75
75
  # for ident(1)
76
- CVS_ID = '$Id: thread.rb 686 2007-11-13 16:42:21Z toki $'
76
+ CVS_ID = '$Id: thread.rb 742 2008-01-13 15:55:53Z toki $'
77
77
 
78
78
  def initialize(count)
79
79
  @count = count
@@ -102,7 +102,7 @@ module Higgs
102
102
 
103
103
  class SharedWork
104
104
  # for ident(1)
105
- CVS_ID = '$Id: thread.rb 686 2007-11-13 16:42:21Z toki $'
105
+ CVS_ID = '$Id: thread.rb 742 2008-01-13 15:55:53Z toki $'
106
106
 
107
107
  def initialize(&work)
108
108
  unless (work) then
@@ -191,7 +191,7 @@ module Higgs
191
191
 
192
192
  class ReadWriteLock
193
193
  # for ident(1)
194
- CVS_ID = '$Id: thread.rb 686 2007-11-13 16:42:21Z toki $'
194
+ CVS_ID = '$Id: thread.rb 742 2008-01-13 15:55:53Z toki $'
195
195
 
196
196
  def initialize
197
197
  @lock = Mutex.new
@@ -201,8 +201,13 @@ module Higgs
201
201
  @count_of_standby_writers = 0
202
202
  @priority_to_writer = true
203
203
  @writing = false
204
+ @read_lock = ReadLock.new(self)
205
+ @write_lock = WriteLock.new(self)
204
206
  end
205
207
 
208
+ attr_reader :read_lock
209
+ attr_reader :write_lock
210
+
206
211
  def __read_lock__
207
212
  @lock.synchronize{
208
213
  while (@writing || (@priority_to_writer && @count_of_standby_writers > 0))
@@ -313,14 +318,6 @@ module Higgs
313
318
  def_delegator :@rw_lock, :__write_unlock__, :unlock
314
319
  end
315
320
 
316
- def read_lock
317
- ReadLock.new(self)
318
- end
319
-
320
- def write_lock
321
- WriteLock.new(self)
322
- end
323
-
324
321
  def to_a
325
322
  [ read_lock, write_lock ]
326
323
  end
@@ -328,7 +325,7 @@ module Higgs
328
325
 
329
326
  class Pool
330
327
  # for ident(1)
331
- CVS_ID = '$Id: thread.rb 686 2007-11-13 16:42:21Z toki $'
328
+ CVS_ID = '$Id: thread.rb 742 2008-01-13 15:55:53Z toki $'
332
329
 
333
330
  class ShutdownException < Exceptions::ShutdownException
334
331
  end
@@ -1,8 +1,8 @@
1
1
  # = transaction manager
2
2
  #
3
3
  # Author:: $Author: toki $
4
- # Date:: $Date: 2007-11-06 00:55:14 +0900 (Tue, 06 Nov 2007) $
5
- # Revision:: $Revision: 674 $
4
+ # Date:: $Date: 2008-01-20 22:28:02 +0900 (Sun, 20 Jan 2008) $
5
+ # Revision:: $Revision: 745 $
6
6
  #
7
7
  # == license
8
8
  # :include:LICENSE
@@ -17,7 +17,7 @@ require 'singleton'
17
17
  module Higgs
18
18
  class TransactionManager
19
19
  # for ident(1)
20
- CVS_ID = '$Id: tman.rb 674 2007-11-05 15:55:14Z toki $'
20
+ CVS_ID = '$Id: tman.rb 745 2008-01-20 13:28:02Z toki $'
21
21
 
22
22
  include Exceptions
23
23
 
@@ -92,6 +92,7 @@ module Higgs
92
92
  if (@read_only == :standby && ! @jlog_apply_dir) then
93
93
  raise ArgumentError, "need for `:jlog_apply_dir' parameter in standby mode"
94
94
  end
95
+ @mvcc_cache = MVCCCache.new
95
96
  @master_cache = SharedWorkCache.new(@master_cache) {|key|
96
97
  (id = @storage.unique_data_id(key) and @secondary_cache[id]) or
97
98
  (value = @storage.fetch(key) and @secondary_cache[@storage.unique_data_id(key)] = value.freeze)
@@ -103,36 +104,23 @@ module Higgs
103
104
  def transaction(read_only=@read_only)
104
105
  r = nil
105
106
  @lock_manager.transaction(read_only) {|lock_handler|
106
- begin
107
- if (TransactionManager.in_transaction?) then
108
- raise 'nested transaction forbidden'
109
- end
107
+ @mvcc_cache.transaction(@storage.change_number) {|snapshot|
110
108
  if (read_only) then
111
- tx = ReadOnlyTransactionContext.new(lock_handler, @storage, @master_cache, @secondary_cache, @decode, @encode)
109
+ tx = ReadOnlyTransactionContext.new(lock_handler, @storage, snapshot, @master_cache, @secondary_cache, @decode, @encode)
112
110
  else
113
111
  if (@read_only) then
114
112
  raise NotWritableError, 'not writable'
115
113
  end
116
- tx = ReadWriteTransactionContext.new(lock_handler, @storage, @master_cache, @secondary_cache, @decode, @encode)
114
+ tx = ReadWriteTransactionContext.new(lock_handler, @storage, snapshot, @master_cache, @secondary_cache, @decode, @encode)
117
115
  end
118
116
  Thread.current[:higgs_current_transaction] = tx
119
117
  r = yield(tx)
120
118
  tx.commit unless read_only
121
- ensure
122
- Thread.current[:higgs_current_transaction] = nil
123
- end
119
+ }
124
120
  }
125
121
  r
126
122
  end
127
123
 
128
- def self.in_transaction?
129
- ! Thread.current[:higgs_current_transaction].nil?
130
- end
131
-
132
- def self.current_transaction
133
- Thread.current[:higgs_current_transaction]
134
- end
135
-
136
124
  def apply_journal_log(not_delete=false)
137
125
  @lock_manager.exclusive{
138
126
  if (@read_only != :standby) then
@@ -163,7 +151,7 @@ module Higgs
163
151
 
164
152
  class TransactionContext
165
153
  # for ident(1)
166
- CVS_ID = '$Id: tman.rb 674 2007-11-05 15:55:14Z toki $'
154
+ CVS_ID = '$Id: tman.rb 745 2008-01-20 13:28:02Z toki $'
167
155
 
168
156
  include Enumerable
169
157
 
@@ -172,30 +160,37 @@ module Higgs
172
160
  end
173
161
  private :deep_copy
174
162
 
175
- def initialize(lock_handler, storage, master_cache, secondary_cache, decode, encode)
163
+ def string_only(key)
164
+ @snapshot.fetch(key, :string_only) {
165
+ properties = @storage.fetch_properties(key) and
166
+ properties['system_properties']['string_only']
167
+ }
168
+ end
169
+ private :string_only
170
+
171
+ def initialize(lock_handler, storage, snapshot, master_cache, secondary_cache, decode, encode)
176
172
  @lock_handler = lock_handler
177
173
  @storage = storage
174
+ @snapshot = snapshot
178
175
  @master_cache = master_cache
179
176
  @secondary_cache = secondary_cache
180
177
  @decode = decode
181
178
  @encode = encode
182
179
 
183
180
  @local_data_cache = Hash.new{|hash, key|
184
- if (@storage.key? key) then
185
- if (@storage.string_only(key)) then
186
- hash[key] = @master_cache[key]
181
+ if (@snapshot.key? @storage, key) then
182
+ if (string_only(key)) then
183
+ hash[key] = @snapshot.fetch(key, :data) { @master_cache[key] }
187
184
  else
188
- hash[key] = @decode.call(@master_cache[key])
185
+ hash[key] = @decode.call(@snapshot.fetch(key, :data) { @master_cache[key] })
189
186
  end
190
187
  end
191
188
  }
192
189
 
193
190
  @local_properties_cache = Hash.new{|hash, key|
194
- if (properties = @storage.fetch_properties(key)) then
195
- hash[key] = deep_copy(properties)
196
- else
197
- hash[key] = { 'system_properties' => {}, 'custom_properties' => {} }
198
- end
191
+ hash[key] = @snapshot.fetch(key, :properties) {
192
+ deep_copy(@storage.fetch_properties(key))
193
+ } || { 'system_properties' => {}, 'custom_properties' => {} }
199
194
  }
200
195
 
201
196
  @locked_map = {}
@@ -205,23 +200,29 @@ module Higgs
205
200
  @ope_map = {}
206
201
  end
207
202
 
203
+ def change_number
204
+ @snapshot.change_number
205
+ end
206
+
208
207
  def locked?(key)
209
208
  @locked_map[key]
210
209
  end
211
210
 
212
211
  def lock(key)
213
212
  unless (@locked_map[key]) then
214
- @lock_handler.lock(key)
213
+ cnum = @snapshot.fetch(key, :data_change_number) {
214
+ @storage.data_change_number(key)
215
+ }
216
+ @lock_handler.lock(key, :data, cnum)
217
+
218
+ cnum = @snapshot.fetch(key, :properties_change_number) {
219
+ @storage.properties_change_number(key)
220
+ }
221
+ @lock_handler.lock(key, :properties, cnum)
222
+
215
223
  @locked_map[key] = true
216
224
  end
217
- nil
218
- end
219
225
 
220
- def unlock(key)
221
- if (@locked_map[key]) then
222
- @lock_handler.unlock(key)
223
- @locked_map[key] = false
224
- end
225
226
  nil
226
227
  end
227
228
 
@@ -268,7 +269,7 @@ module Higgs
268
269
  if (@local_data_cache.key? key) then
269
270
  return true
270
271
  end
271
- if (@storage.key? key) then
272
+ if (@snapshot.key? @storage, key) then
272
273
  return true
273
274
  end
274
275
  end
@@ -286,7 +287,7 @@ module Higgs
286
287
  yield(key)
287
288
  end
288
289
  end
289
- @storage.each_key do |key|
290
+ @snapshot.each_key(@storage) do |key|
290
291
  lock(key)
291
292
  if (@ope_map[key] != :delete) then
292
293
  unless (@local_data_cache.key? key) then
@@ -356,11 +357,11 @@ module Higgs
356
357
  if (properties = @local_properties_cache[key]) then
357
358
  case (name)
358
359
  when :identity
359
- @storage.identity(key)
360
+ @snapshot.fetch(key, :identity) { @storage.identity(key) }
360
361
  when :data_change_number
361
- @storage.data_change_number(key)
362
+ @snapshot.fetch(key, :data_change_number) { @storage.data_change_number(key) }
362
363
  when :properties_change_number
363
- @storage.properties_change_number(key)
364
+ @snapshot.fetch(key, :properties_change_number) { @storage.properties_change_number(key) }
364
365
  when Symbol
365
366
  properties['system_properties'][name.to_s]
366
367
  when String
@@ -416,11 +417,11 @@ module Higgs
416
417
  if (self.key? key) then # lock
417
418
  case (name)
418
419
  when :identity
419
- return @storage.identity(key) != nil
420
+ return @snapshot.fetch(key, :identity) { @storage.identity(key) } != nil
420
421
  when :data_change_number
421
- return @storage.data_change_number(key) != nil
422
+ return @snapshot.fetch(key, :data_change_number) { @storage.data_change_number(key) } != nil
422
423
  when :properties_change_number
423
- return @storage.properties_change_number(key) != nil
424
+ return @snapshot.fetch(key, :properties_change_number) { @storage.properties_change_number(key) } != nil
424
425
  when Symbol
425
426
  return (@local_properties_cache[key]['system_properties'].key? name.to_s)
426
427
  when String
@@ -436,13 +437,13 @@ module Higgs
436
437
  unless (self.key? key) then # lock
437
438
  raise IndexError, "not exist properties at key: #{key}"
438
439
  end
439
- if (value = @storage.identity(key)) then
440
+ if (value = @snapshot.fetch(key, :identity) { @storage.identity(key) }) then
440
441
  yield(:identity, value)
441
442
  end
442
- if (value = @storage.data_change_number(key)) then
443
+ if (value = @snapshot.fetch(key, :data_change_number) { @storage.data_change_number(key) }) then
443
444
  yield(:data_change_number, value)
444
445
  end
445
- if (value = @storage.properties_change_number(key)) then
446
+ if (value = @snapshot.fetch(key, :properties_change_number) { @storage.properties_change_number(key) }) then
446
447
  yield(:properties_change_number, value)
447
448
  end
448
449
  @local_properties_cache[key]['system_properties'].each_pair do |name, value|
@@ -507,22 +508,77 @@ module Higgs
507
508
 
508
509
  def commit
509
510
  write_list = write_list()
510
- unless (write_list.empty?) then
511
- @storage.write_and_commit(write_list)
511
+ if (write_list.empty?) then
512
+ return
513
+ end
514
+
515
+ @lock_handler.critical{
516
+ @lock_handler.check_collision{|key, type|
517
+ case (type)
518
+ when :data
519
+ @storage.data_change_number(key)
520
+ when :properties
521
+ @storage.properties_change_number(key)
522
+ else
523
+ raise "unknown type: #{type}"
524
+ end
525
+ }
526
+
527
+ old_write_list = []
512
528
  for ope, key, value in write_list
513
529
  case (ope)
514
530
  when :write
515
- @master_cache.delete(key)
531
+ if (@storage.key? key) then
532
+ properties = Marshal.load(Marshal.dump(@storage.fetch_properties(key)))
533
+ old_write_list << [ :value, key, :data, @master_cache[key] ]
534
+ old_write_list << [ :value, key, :properties, properties ]
535
+ old_write_list << [ :value, key, :identity, @storage.identity(key) ]
536
+ old_write_list << [ :value, key, :string_only, properties['system_properties']['string_only'] ]
537
+ old_write_list << [ :value, key, :data_change_number, @storage.data_change_number(key) ]
538
+ old_write_list << [ :value, key, :properties_change_number, @storage.properties_change_number(key) ]
539
+ else
540
+ old_write_list << [ :none, key ]
541
+ end
542
+ when :system_properties, :custom_properties
543
+ if (@storage.key? key) then
544
+ properties = Marshal.load(Marshal.dump(@storage.fetch_properties(key)))
545
+ old_write_list << [ :value, key, :properties, properties ]
546
+ old_write_list << [ :value, key, :properties_change_number, @storage.properties_change_number(key) ]
547
+ else
548
+ old_write_list << [ :none, key ]
549
+ end
516
550
  when :delete
551
+ if (@storage.key? key) then
552
+ properties = Marshal.load(Marshal.dump(@storage.fetch_properties(key)))
553
+ old_write_list << [ :value, key, :data, @master_cache[key] ]
554
+ old_write_list << [ :value, key, :properties, properties ]
555
+ old_write_list << [ :value, key, :identity, @storage.identity(key) ]
556
+ old_write_list << [ :value, key, :string_only, properties['system_properties']['string_only'] ]
557
+ old_write_list << [ :value, key, :data_change_number, @storage.data_change_number(key) ]
558
+ old_write_list << [ :value, key, :properties_change_number, @storage.properties_change_number(key) ]
559
+ end
560
+ else
561
+ raise "unknown operation: #{ope}"
562
+ end
563
+ end
564
+ @snapshot.write_old_values(old_write_list)
565
+
566
+ for ope, key, value in write_list
567
+ case (ope)
568
+ when :write, :delete
517
569
  @master_cache.delete(key)
518
- @secondary_cache.delete(key)
519
570
  end
520
571
  @local_properties_cache.delete(key)
521
572
  end
522
573
  @update_system_properties.clear
523
574
  @update_custom_properties.clear
524
575
  @ope_map.clear
525
- end
576
+
577
+ @storage.write_and_commit(write_list)
578
+ @snapshot.ref_count_down
579
+ @snapshot.ref_count_up(@storage.change_number)
580
+ }
581
+
526
582
  nil
527
583
  end
528
584