xamplr 1.9.13 → 1.9.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -76,34 +76,40 @@ module Xampl
76
76
  @@default_persister_options[:format] = format
77
77
  end
78
78
 
79
- def Xampl.enable_persister(name, kind=nil, format=nil)
80
- kind = kind || Xampl.default_persister_kind
81
- format = format || Xampl.default_persister_format
79
+ def Xampl.create_named_persister(name, kind, arg=nil)
80
+ raise NoAnonymousPersisters.new unless name # there is no such thing as an anonymous persister, maybe later
82
81
 
83
- @@persister = @@known_persisters[name]
82
+ persister = @@known_persisters[name]
83
+ return persister if persister
84
84
 
85
- if @@persister then
86
- # @@persister.open # this won't work
87
- # TODO -- if we know the persister, why are we being so anal about kind and format???
85
+ persister_class = @@persister_kinds[kind]
86
+ return nil unless persister_class
88
87
 
89
- kind = @@persister.kind || kind
90
- format = @@persister.format || format
88
+ persister = persister_class.new(name, :xml_format, arg)
89
+ @@known_persisters[name] = persister
91
90
 
92
- if kind and kind != @@persister.kind then
93
- raise IncompatiblePersisterRequest.new(@@persister, "kind", kind, @@persister.kind)
94
- end
95
- if format and format != @@persister.format then
96
- raise IncompatiblePersisterRequest.new(@@persister, "format", format, @@persister.format)
97
- end
98
- end
91
+ return persister
92
+ end
99
93
 
100
- unless @@persister then
101
- @@persister = @@persister_kinds[kind].new(name, format)
102
- if (nil != name) then
103
- @@known_persisters[name] = @@persister
104
- end
105
- end
94
+ def Xampl.find_named_persister(name)
95
+ persister = @@known_persisters[name]
96
+ end
97
+
98
+ def Xampl.enable_named_persister(name)
99
+ persister = @@known_persisters[name]
100
+ raise NoPersisterNamed.new(name) unless persister
101
+
102
+ @@persister = persister
103
+ end
104
+
105
+ def Xampl.enable_persister(name, preferred_kind=nil)
106
+ # you'd better know what you are doing if you call this
107
+
108
+ raise NoPersisterNamed.new unless name
106
109
 
110
+ preferred_kind = preferred_kind || Xampl.default_persister_kind
111
+
112
+ @@persister = @@known_persisters[name] || Xampl.create_named_persister(name, preferred_kind, nil)
107
113
  @@persister
108
114
  end
109
115
 
@@ -111,11 +117,12 @@ module Xampl
111
117
  puts "Known Persisters:: --------------------------"
112
118
  @@known_persisters.each { |n, k| puts " #{n} #{k}" }
113
119
  puts "---------------------------------------------"
120
+ puts caller(0)
114
121
  end
115
122
 
116
123
  def Xampl.flush_persister_caches
117
124
  Xampl.print_known_persisters
118
- @persister.close
125
+ @@persister.close
119
126
  @@known_persisters.delete(@@persister.name)
120
127
  Xampl.print_known_persisters
121
128
  end
@@ -137,19 +144,21 @@ module Xampl
137
144
  end
138
145
 
139
146
  def Xampl.drop_persister(name)
140
- Xampl.print_known_persisters
147
+ # Xampl.print_known_persisters
141
148
  p = @@known_persisters[name]
142
149
  p.close if p
143
150
  @@known_persisters.delete(name)
144
- Xampl.print_known_persisters
151
+ # Xampl.print_known_persisters
145
152
  end
146
153
 
147
154
  def Xampl.add_lexical_indexs(indexes)
148
155
  case Xampl.default_persister_kind
149
156
  when :tokyo_cabinet then
150
157
  Xampl::TokyoCabinetPersister.add_lexical_indexs(indexes)
151
- when :monto then
152
- Xampl::MongoPersister.add_lexical_indexs(indexes)
158
+ when :redis then
159
+ Xampl::RedisPersister.add_lexical_indexs(indexes)
160
+ #when :mongo then
161
+ # Xampl::MongoPersister.add_lexical_indexs(indexes)
153
162
  else
154
163
  raise IncompatiblePersisterConfiguration.new(Xampl.default_persister_kind, "lexical_indexes")
155
164
  end
@@ -159,8 +168,10 @@ module Xampl
159
168
  case Xampl.default_persister_kind
160
169
  when :tokyo_cabinet then
161
170
  Xampl::TokyoCabinetPersister.add_numerical_indexs(indexes)
162
- when :mongo then
163
- Xampl::MongoPersister.add_numerical_indexs(indexes)
171
+ when :redis then
172
+ Xampl::RedisPersister.add_numerical_indexs(indexes)
173
+ #when :mongo then
174
+ # Xampl::MongoPersister.add_numerical_indexs(indexes)
164
175
  else
165
176
  raise IncompatiblePersisterConfiguration.new(Xampl.default_persister_kind, "numerical_indexs")
166
177
  end
@@ -213,7 +224,7 @@ module Xampl
213
224
  @@xampl_lock.synchronize(:EX) do
214
225
  begin
215
226
  initial_persister = @@persister
216
- Xampl.enable_persister(name, kind, format)
227
+ Xampl.enable_persister(name, kind)
217
228
 
218
229
  original_automatic = @@persister.automatic
219
230
 
@@ -278,7 +289,6 @@ module Xampl
278
289
  end
279
290
  end
280
291
 
281
- #def Xampl.transaction_using_proc(thing, kind=nil, automatic=true, format=nil, & block)
282
292
  def Xampl.transaction(thing, kind=nil, automatic=true, format=nil, & block)
283
293
  # this method cannot account for returns in transactions (proc vs lambda/method issues)
284
294
  if String === thing then
@@ -289,13 +299,89 @@ module Xampl
289
299
  raise XamplException.new("can't base a transaction on a #{thing.class.name} (#{thing})")
290
300
  end
291
301
 
302
+ if block_given? then
303
+ @@xampl_lock.synchronize(:EX) do
304
+ rollback = true
305
+ exception = nil
306
+ begin
307
+ initial_persister = @@persister
308
+ Xampl.enable_persister(name, kind)
309
+
310
+ original_automatic = @@persister.automatic
311
+
312
+ begin
313
+ #TODO -- impose some rules on nested transactions/enable_persisters??
314
+
315
+ Xampl.auto_persistence(automatic)
316
+
317
+ result = yield
318
+
319
+ rollback = false
320
+ Xampl.block_future_changes(true)
321
+ Xampl.sync
322
+ return result
323
+ rescue => e
324
+ # puts e.backtrace
325
+ exception = e
326
+ ensure
327
+ Xampl.block_future_changes(false)
328
+ Xampl.auto_persistence(original_automatic)
329
+
330
+ if rollback then
331
+ # we get here if the transaction block finishes early, for one of three reasons:
332
+ # 1) exception
333
+ # 2) throw
334
+ # 3) explicit return in the block
335
+ # it is arguable that throw and returns are 'okay', or normal exits from the block... I don't know???
336
+
337
+ if exception then
338
+ # the early finish was caused by an exception
339
+
340
+ Xampl.rollback
341
+ else
342
+ # this is the throw/explicit-return
343
+
344
+ #TODO -- is this a good idea??
345
+ Xampl.block_future_changes(true)
346
+ Xampl.sync
347
+
348
+
349
+ #TODO -- uncomment this, it's handy
350
+ # STDERR.puts "---------"
351
+ # STDERR.puts "Either a return or a throw from a transaction. The DB is synced, but this is not a good thing to be doing."
352
+ # STDERR.puts caller(0)
353
+ # STDERR.puts "---------"
354
+ end
355
+ end
356
+ end
357
+ ensure
358
+ @@persister = initial_persister
359
+
360
+ if exception then
361
+ raise RuntimeError, "ROLLBACK(#{__LINE__}):: #{exception}", exception.backtrace
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
367
+
368
+ def Xampl.transaction_not_so_good(thing, kind=nil, automatic=true, format=nil, & block)
369
+ # this method cannot account for returns in transactions (proc vs lambda/method issues)
370
+ if String === thing then
371
+ name = thing
372
+ elsif XamplObject === thing then
373
+ name = thing.persister.name
374
+ else
375
+ raise XamplException.new("can't base a transaction on a #{thing.class.name} (#{thing})")
376
+ end
377
+
292
378
  if block_given? then
293
379
  @@xampl_lock.synchronize(:EX) do
294
380
  # if true then
295
381
  begin
296
382
  # @@xampl_lock.sync_lock(:EX)
297
383
  initial_persister = @@persister
298
- Xampl.enable_persister(name, kind, format)
384
+ Xampl.enable_persister(name, kind)
299
385
 
300
386
  rollback = true
301
387
  exception = nil
@@ -305,22 +391,32 @@ module Xampl
305
391
  #TODO -- impose some rules on nested transactions/enable_persisters??
306
392
 
307
393
  Xampl.auto_persistence(automatic)
394
+
308
395
  result = yield
396
+
397
+ rollback = false
309
398
  Xampl.block_future_changes(true)
310
399
  Xampl.sync
311
- rollback = false
312
400
  return result
313
401
  rescue => e
402
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
403
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
314
404
  exception = e
315
405
  ensure
316
406
  Xampl.block_future_changes(false)
317
407
  Xampl.auto_persistence(original_automatic)
408
+
409
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
318
410
  if rollback then
411
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
412
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
319
413
  # we get here if the transaction block finishes early
320
414
  if exception then
415
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
321
416
  # the early finish was caused by an exception
322
417
  raise RuntimeError, "ROLLBACK(#{__LINE__}):: #{exception}", exception.backtrace
323
418
  else
419
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
324
420
  # How could we have arrived at this point???
325
421
  # Well, I don't know all the reasons, but the ones I do know are:
326
422
  # - return was used in the block passed into the transaction
@@ -337,32 +433,30 @@ module Xampl
337
433
  STDERR.puts(trace)
338
434
  end
339
435
  STDERR.puts "---------"
340
-
341
- =begin
342
-
343
- begin
344
- puts "#{ __FILE__ }:#{ __LINE__ } [#{__method__}] "
345
- Xampl.block_future_changes(true)
346
- puts "#{ __FILE__ }:#{ __LINE__ } [#{__method__}] "
347
- Xampl.sync
348
- rollback = false
349
- rescue => e
350
- puts "#{ __FILE__ }:#{ __LINE__ } [#{__method__}] "
351
- # so we know the persister had a problem
352
- puts "PERSISTER ERROR(#{__LINE__}) #{ e }"
353
- ensure
354
- puts "#{ __FILE__ }:#{ __LINE__ } [#{__method__}] "
355
- Xampl.block_future_changes(false)
356
- end
357
-
358
- =end
359
436
  end
437
+ else
438
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
439
+ end
440
+
441
+ if rollback then
442
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
443
+ Xampl.rollback
444
+ rollback = false
445
+ else
446
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
360
447
  end
361
- Xampl.rollback if rollback
362
448
  @@persister = initial_persister
363
449
  end
364
- raise exception if exception
365
- # ensure
450
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
451
+ if exception
452
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
453
+ raise exception
454
+ else
455
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback }"
456
+ end
457
+ ensure
458
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME" if rollback
459
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] rollback: #{ rollback } ????????????" if rollback
366
460
  # @@xampl_lock.sync_unlock
367
461
  end
368
462
  end
@@ -382,7 +476,7 @@ module Xampl
382
476
  if block_given? then
383
477
  @@xampl_lock.synchronize(:EX) do
384
478
  initial_persister = @@persister
385
- Xampl.enable_persister(name, kind, format)
479
+ Xampl.enable_persister(name, kind)
386
480
  target_persister = @@persister
387
481
 
388
482
  rollback = true
@@ -438,7 +532,7 @@ module Xampl
438
532
 
439
533
  if block_given? then
440
534
  initial_persister = @@persister
441
- Xampl.enable_persister(name, target_persister.kind, target_persister.format)
535
+ Xampl.enable_persister(name, target_persister.kind)
442
536
 
443
537
  rollback = true
444
538
  original_automatic = @@persister.automatic
@@ -72,17 +72,9 @@ module Xampl
72
72
  end
73
73
 
74
74
  def has_changed(xampl)
75
- #raise XamplException.new(:live_across_rollback) if @rolled_back
76
- # puts "!!!! has_changed #{xampl} #{xampl.get_the_index} -- persist required: #{xampl.persist_required}"
77
75
  if xampl.persist_required && xampl.is_changed then
78
- unless self == xampl.persister
79
- raise MixedPersisters.new(xampl.persister, self)
80
- end
76
+ raise MixedPersisters.new(xampl.persister, self) unless self == xampl.persister
81
77
  @changed[xampl] = xampl
82
- # puts "!!!! change recorded ==> #{@changed.size}/#{count_changed} #{@changed.object_id} !!!!"
83
- # @changed.each{ | thing, ignore |
84
- # puts " changed: #{thing}, index: #{thing.get_the_index}, changed: #{thing.is_changed}"
85
- # }
86
78
  end
87
79
  end
88
80
 
@@ -132,15 +124,7 @@ module Xampl
132
124
  end
133
125
 
134
126
  def represent(xampl, mentions=[])
135
- #puts "REPRESENT #{xampl} load needed: #{xampl.load_needed}"
136
- # return nil if xampl.load_needed
137
- rep = nil
138
- case xampl.default_persister_format || @format
139
- when nil, :xml_format then
140
- rep = xampl.persist("", mentions)
141
- when :ruby_format then
142
- rep = xampl.to_ruby(mentions)
143
- end
127
+ rep = xampl.persist("", mentions)
144
128
  return rep
145
129
  rescue => e
146
130
  msg = "Failed to represent #{ xampl } due to: #{ e }"
@@ -150,15 +134,15 @@ module Xampl
150
134
  end
151
135
 
152
136
  def realise(representation, target=nil)
153
- # Normally we'd expect to see the representation in the @format format, but
154
- # that isn't necessarily the case. Try to work out what the format might be...
155
-
156
- #TODO -- this is a bit brutal, but it should work (it is the rule is that this is supposed to be UTF-8)
137
+ # This is a bit brutal, but it works (and, anyway, it *is* the rule is that this is supposed to be UTF-8)
157
138
  representation_fixed = representation.encode('UTF-8', :invalid => :replace, :undef => :replace)
158
- # puts "#{ ::File.basename __FILE__ }:#{ __LINE__ } [#{__method__}] ENCODING: #{ representation.encoding } -> #{ representation_fixed.encoding }"
159
139
 
160
140
  xampl = nil
161
- if representation_fixed =~ /^</ then
141
+
142
+ # These days 'new' representations can only be XML. Historically it could have been Ruby. Check the
143
+ # representations (quickly) and choose appropriately.
144
+ if '<' == representation_fixed[0] then
145
+ # well it isn't ruby, so it must be XML. Of course this means no leading whitespace, which happens to be true.
162
146
  xampl = XamplObject.realise_from_xml_string(representation_fixed, target)
163
147
  else
164
148
  xampl = XamplObject.from_ruby(representation_fixed, target)
@@ -364,13 +348,14 @@ module Xampl
364
348
  end
365
349
 
366
350
  begin
367
- if require 'mongo' then
368
- require "xamplr/persisters/mongo"
351
+ if require 'redis' then
352
+ require 'weakref'
353
+ require "xamplr/persisters/redis"
369
354
  end
370
355
  rescue LoadError => e
371
- # Well. No MongoDB.
356
+ # Well. No redis.
372
357
  rescue
373
- # Well. No MongoDB.
358
+ # Well. No redis.
374
359
  end
375
360
 
376
361
  end
@@ -2,7 +2,7 @@ module Xampl
2
2
 
3
3
  class DumbPersister < Persister
4
4
 
5
- def initialize(name=nil, format=nil)
5
+ def initialize(name=nil, format=nil, ignore=nil)
6
6
  super(name, format)
7
7
 
8
8
  @module_map = {}
@@ -5,7 +5,8 @@ module Xampl
5
5
 
6
6
  class FilesystemPersister < AbstractCachingPersister
7
7
 
8
- def initialize(name=nil, format=nil, root=File.join(".", "repo"))
8
+ def initialize(name=nil, format=nil, root=nil)
9
+ root = File.join(".", "repo") if root.nil?
9
10
  super(root, name, format)
10
11
  end
11
12
 
@@ -5,6 +5,7 @@ module Xampl
5
5
  class InMemoryPersister < Persister
6
6
 
7
7
  def initialize(name=nil, format=nil, capacity=20)
8
+ capacity ||= 20
8
9
  super(name, format)
9
10
 
10
11
  @module_map = {}
@@ -0,0 +1,449 @@
1
+ module Xampl
2
+
3
+ class RedisPersister < Persister
4
+
5
+ attr_reader :repo_name,
6
+ :instance_options,
7
+ :client, # currently it's an instance of ::Redis from the redis-rb library
8
+ :suggested_repo_properties,
9
+ :repo_properties
10
+
11
+ @@default_redis_options = {
12
+ :repo_properties => {
13
+ # DB Properties, maybe only set when the DB is created for the first time.
14
+ :mentions => true,
15
+ },
16
+
17
+ # Connect Properties
18
+ :thread_safe => true, # redis connections will be thread safe
19
+ :redis_server => "redis://127.0.0.1:6379/0", #This is the format expected by redis-rb, just use it
20
+ :clobbering_allowed => false,
21
+ :allow_connections => true,
22
+ :connect_to_known => true, # will connect to repos already in the redis db
23
+ :connect_to_unknown => true, # will connect to repose not in the redis db
24
+ :testing => false
25
+ }
26
+
27
+ REPOSITORIES_KEY = "XAMPL::REPOSITORIES"
28
+
29
+ def initialize(name=nil, format=nil, options={})
30
+ super(name, format)
31
+
32
+ @repo_name = name
33
+ # puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] @@default_redis_options: #{ @@default_redis_options.inspect }"
34
+ # puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] Xampl.raw_persister_options: #{ Xampl.raw_persister_options.inspect }"
35
+ # puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] options: #{ options.inspect }"
36
+
37
+ @instance_options = {}
38
+ @instance_options = @instance_options.merge(@@default_redis_options)
39
+ @instance_options = @instance_options.merge(Xampl.raw_persister_options)
40
+ @instance_options = @instance_options.merge(options) if options
41
+
42
+ @suggested_repo_properties = @instance_options.delete(:repo_properties)
43
+
44
+ clear_cache
45
+ ensure_connected
46
+ end
47
+
48
+ def RedisPersister.kind
49
+ :redis
50
+ end
51
+
52
+ def kind
53
+ RedisPersister.kind
54
+ end
55
+
56
+ def ensure_connected
57
+ return if @client
58
+ return unless instance_options[:allow_connections]
59
+
60
+ server = @instance_options[:redis_server]
61
+ thread_safe = @instance_options[:thread_safe]
62
+ @client = Redis.connect(:url => server, :thread_safe => thread_safe)
63
+
64
+ # This check is necessary to make sure that the connection is made, otherwise the exception will be sometime in the future
65
+ # the redis exceptions are good enough, so don't bother trapping right here
66
+ @client.ping
67
+
68
+ # check to see if the repository with this name is known (in redis) already
69
+ load_repo_properties
70
+
71
+ if @repo_properties && !@instance_options[:connect_to_known] then
72
+ ensure_disconnected
73
+ raise IncompatiblePersisterConfiguration.new('redis', "prevent connections to existing repos named: '#{ repo_name }' in #{ server }")
74
+ end
75
+ if @repo_properties.nil? && !@instance_options[:connect_to_unknown] then
76
+ ensure_disconnected
77
+ raise IncompatiblePersisterConfiguration.new('redis', "prevent connections to unknown repos named: '#{ repo_name }' in #{ server }")
78
+ end
79
+
80
+ return if @repo_properties
81
+
82
+ # if it is unknown, then set it up
83
+
84
+ @repo_properties = {}
85
+ suggested_repo_properties.each do |k, v|
86
+ @repo_properties[k] = v
87
+ end
88
+ @repo_properties['name'] = repo_name
89
+ @repo_properties['created_at'] = DateTime.now.to_s
90
+
91
+ @client.multi do
92
+ @client.mapped_hmset(repo_properties_key, @repo_properties)
93
+ @client.sadd(REPOSITORIES_KEY, repo_name)
94
+ end
95
+
96
+ load_repo_properties
97
+ end
98
+
99
+ def ensure_disconnected
100
+ return unless client
101
+ return unless instance_options[:allow_connections]
102
+
103
+ @client.quit
104
+ ensure
105
+ @repo_properties = nil
106
+ @client = nil
107
+ end
108
+
109
+ def clobber
110
+ # TODO -- this is a BAD idea if there are any other connections to this repo (i.e. in different processes)
111
+
112
+ unless @instance_options[:clobbering_allowed] then
113
+ raise IncompatiblePersisterConfiguration.new('redis', "clobbering is not enabled for this connection to repo: '#{ repo_name }' in #{ @instance_options[:redis_server] }")
114
+ end
115
+
116
+ #TODO -- getting the keys outside the multi might allow some new key to sneak in there
117
+ keys = @client.keys("#{ common_key_prefix }*")
118
+ @client.multi do
119
+ @client.del(repo_properties_key)
120
+ @client.srem(REPOSITORIES_KEY, repo_name)
121
+
122
+ keys.each do |key|
123
+ @client.del(key)
124
+ end
125
+ end
126
+
127
+ ensure_disconnected
128
+ end
129
+
130
+ def repo_properties_key
131
+ key = "XAMPL::PROPERTIES::#{ @repo_name }"
132
+ return key
133
+ end
134
+
135
+ def load_repo_properties
136
+ key = repo_properties_key()
137
+ @repo_properties = @client.hgetall(key)
138
+ @repo_properties = nil if @repo_properties.empty?
139
+ end
140
+
141
+ def clear_cache
142
+ @cache_hits = 0
143
+ @cache = {}
144
+ @new_cache = {}
145
+ end
146
+
147
+ alias fresh_cache clear_cache
148
+
149
+ def close
150
+ ensure_disconnected
151
+ clear_cache
152
+ end
153
+
154
+ def common_key_prefix
155
+ "XAMPL::#{ @repo_name }::"
156
+ end
157
+
158
+ def key_for_class(klass, index)
159
+ #NOTE -- the XAMPL::#{ @repo_name }:: is a prefix common to all keys specific to this repository
160
+ "#{ common_key_prefix }#{ klass.name }[#{ index }]"
161
+ end
162
+
163
+ def key_for_xampl(xampl)
164
+ key_for_class(xampl.class, xampl.get_the_index)
165
+ end
166
+
167
+ def known_repos
168
+ return @client.smembers(REPOSITORIES_KEY)
169
+ end
170
+
171
+ def perm_cache(xampl)
172
+ raise NotXamplPersistedObject.new(xampl) unless xampl.kind_of?(XamplPersistedObject)
173
+
174
+ key = key_for_xampl(xampl)
175
+ existing = @cache[key]
176
+
177
+ begin
178
+ # raise DuplicateXamplInPersister.new(existing, xampl, self) if existing && (existing.weakref_alive?) && (existing.__getobj__ != xampl)
179
+ raise DuplicateXamplInPersister.new(existing, xampl, self) if existing && (existing.__getobj__ != xampl)
180
+ rescue WeakRef::RefError => e
181
+ # key is there but the original object isn't...
182
+ end
183
+
184
+ @cache[key] = WeakRef.new(xampl)
185
+ end
186
+
187
+ def perm_uncache(xampl)
188
+ raise NotXamplPersistedObject.new(xampl) unless xampl.kind_of?(XamplPersistedObject)
189
+
190
+ key = key_for_xampl(xampl)
191
+ @cache.delete(key).__getobj__
192
+ end
193
+
194
+ def cache(xampl)
195
+ # this is called by xampl for the temporary new_cache
196
+ raise NotXamplPersistedObject.new(xampl) unless xampl.kind_of?(XamplPersistedObject)
197
+
198
+ key = key_for_xampl(xampl)
199
+
200
+ existing = @new_cache[key]
201
+ raise DuplicateXamplInPersister.new(existing, xampl, self) if existing && (existing != xampl)
202
+
203
+ existing = @cache[key]
204
+ begin
205
+ # raise DuplicateXamplInPersister.new(existing, xampl, self) if existing && (existing.weakref_alive?) && (existing.__getobj__ != xampl)
206
+ raise DuplicateXamplInPersister.new(existing, xampl, self) if existing && (existing.__getobj__ != xampl)
207
+ rescue WeakRef::RefError => e
208
+ # key is there but the original object isn't...
209
+ end
210
+
211
+ @new_cache[key] = xampl
212
+ end
213
+
214
+ def uncache(xampl)
215
+ # this is called by xampl for the temporary new_cache
216
+ raise NotXamplPersistedObject.new(xampl) unless xampl.kind_of?(XamplPersistedObject)
217
+
218
+ key = key_for_xampl(xampl)
219
+ @new_cache.delete(key)
220
+ end
221
+
222
+ def in_perm_cache?(klass, index)
223
+ key = key_for_class(klass, index)
224
+ xampl = @cache[key]
225
+
226
+ (xampl && xampl.weakref_alive?) ? true : false
227
+ end
228
+
229
+ alias in_cache? in_perm_cache?
230
+
231
+ def in_new_cache?(klass, index)
232
+ key = key_for_class(klass, index)
233
+ @new_cache.include?(key)
234
+ end
235
+
236
+ def in_any_cache?(klass, index)
237
+ in_new_cache?(klass, index) || in_cache?(klass, index)
238
+ end
239
+
240
+ def read_from_cache(klass, index, target=nil)
241
+
242
+ key = key_for_class(klass, index)
243
+
244
+ xampl = @cache[key]
245
+ begin
246
+ xampl = xampl.__getobj__ if xampl
247
+ rescue WeakRef::RefError => e
248
+ #not there
249
+ xampl = nil
250
+ end
251
+ # xampl = (xampl && xampl.weakref_alive?) ? xampl.__getobj__ : nil
252
+
253
+ unless xampl then
254
+ xampl = @new_cache[key]
255
+ end
256
+
257
+ return nil, target unless xampl
258
+
259
+ if target and target != xampl then
260
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
261
+ target.invalidate
262
+ raise XamplException.new(:cache_conflict)
263
+ end
264
+ unless xampl.load_needed then
265
+ @cache_hits = @cache_hits + 1
266
+ return xampl, target
267
+ end
268
+ return xampl, xampl
269
+ end
270
+
271
+ def sync_done
272
+ # simply moves the new_cache to the permanent cache
273
+ (@new_cache || {}).each do |key, xampl|
274
+ @cache[key] = WeakRef.new(xampl)
275
+ end
276
+ @new_cache = {}
277
+ end
278
+
279
+ def write(xampl)
280
+ unless xampl.get_the_index
281
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
282
+ raise NotXamplPersistedObject.new(xampl)
283
+ end
284
+
285
+ #TODO -- honour the mentions config information (FROM THE DB not the configuration!!)
286
+ mentions = []
287
+ xml = represent(xampl, mentions)
288
+ key = key_for_xampl(xampl)
289
+
290
+ #TODO save the modified-time-like value to support multi processing
291
+
292
+ # puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] redis #{ self }"
293
+ # puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] write: #{ xampl } --> #{ xml }"
294
+ # puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] key: #{ key }"
295
+
296
+ client.set(key, xml)
297
+ @write_count = @write_count + 1
298
+ xampl.changes_accepted
299
+ return true
300
+
301
+ rescue NotXamplPersistedObject => nxpo
302
+ raise nxpo
303
+ rescue => e
304
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] #{ e }"
305
+ puts e.backtrace
306
+ return false
307
+ end
308
+
309
+ def read(klass, pid, target=nil)
310
+ xampl, target = read_from_cache(klass, pid, target)
311
+ return xampl if xampl and !target
312
+
313
+ key = key_for_class(klass, pid)
314
+ xml = client.get(key)
315
+ unless xml
316
+ puts "#{File.basename(__FILE__)}:#{__LINE__} [#{ __method__ }] TEST ME"
317
+ return nil
318
+ end
319
+
320
+ xampl = realise(xml, target)
321
+ Xampl.store_in_cache(@cache, xampl, self) { xampl }
322
+ xampl.introduce_persister(self)
323
+
324
+ @read_count = @read_count + 1
325
+ xampl.changes_accepted
326
+ @changed.delete(xampl)
327
+ return xampl
328
+ end
329
+
330
+ def rollback_cleanup
331
+
332
+ @new_cache.each { |name, xampl|
333
+ if xampl then
334
+ @changed.delete(xampl)
335
+ xampl.invalidate
336
+
337
+ # map.each { |name2, map2|
338
+ # if map2 then
339
+ # map2.each { |pid, xampl|
340
+ # @changed.delete(xampl)
341
+ # xampl.invalidate
342
+ # }
343
+ # end
344
+ # }
345
+ end
346
+ }
347
+ @changed.each { |xampl, ignore|
348
+ xampl.force_load
349
+ }
350
+ @new_cache = {}
351
+
352
+ super
353
+ end
354
+
355
+ =begin
356
+
357
+
358
+
359
+
360
+
361
+
362
+ def backup(base_path)
363
+ #TODO
364
+ end
365
+
366
+ def do_sync_write
367
+ #TODO
368
+ end
369
+
370
+ def done_sync_write
371
+ #TODO
372
+ end
373
+
374
+ def expunge(xampl)
375
+ #TODO
376
+ end
377
+
378
+ def find_mentions_of(xampl)
379
+ #TODO
380
+ end
381
+
382
+ def find_meta(hint=false)
383
+ #TODO
384
+ end
385
+
386
+ def find_pids(hint=false)
387
+ #TODO
388
+ end
389
+
390
+ def find_xampl(hint=false)
391
+ #TODO
392
+ end
393
+
394
+ def how_indexed(xampl)
395
+ #TODO
396
+ end
397
+
398
+ def inspect
399
+ #TODO
400
+ end
401
+
402
+ def note_errors(msg="TokyoCabinet Error:: %s\n")
403
+ #TODO
404
+ end
405
+
406
+ def open_tc_db
407
+ #TODO
408
+ end
409
+
410
+ def optimise(opts={})
411
+ #TODO
412
+ end
413
+
414
+ def query(hint=false)
415
+ #TODO
416
+ end
417
+
418
+ def query_implemented
419
+ #TODO
420
+ end
421
+
422
+ def read_representation(klass, pid)
423
+ #TODO
424
+ end
425
+
426
+ def remove_all_mention(root, xampl)
427
+ #TODO
428
+ end
429
+
430
+ def setup_db
431
+ #TODO
432
+ end
433
+
434
+ def start_sync_write
435
+ #TODO
436
+ end
437
+
438
+ def to_s
439
+ #TODO
440
+ end
441
+
442
+ =end
443
+
444
+ end
445
+
446
+
447
+ Xampl.register_persister_kind(RedisPersister)
448
+ end
449
+