xamplr 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. data/CHANGES.txt +13 -0
  2. data/LICENSE +3 -0
  3. data/README.rdoc +26 -0
  4. data/README.rdoc.orig +118 -0
  5. data/Rakefile +85 -0
  6. data/VERSION.yml +4 -0
  7. data/examples/random-people-shared-addresses/Makefile +16 -0
  8. data/examples/random-people-shared-addresses/batch-load-users.rb +83 -0
  9. data/examples/random-people-shared-addresses/find-mentions.rb +47 -0
  10. data/examples/random-people-shared-addresses/find-people-by-address.rb +104 -0
  11. data/examples/random-people-shared-addresses/optimise.rb +16 -0
  12. data/examples/random-people-shared-addresses/people.rb +35 -0
  13. data/examples/random-people-shared-addresses/query.rb +75 -0
  14. data/examples/random-people-shared-addresses/query2.rb +73 -0
  15. data/examples/random-people-shared-addresses/random-names.csv +10000 -0
  16. data/examples/random-people-shared-addresses/settings.rb +3 -0
  17. data/examples/random-people-shared-addresses/what-to-query-on.rb +82 -0
  18. data/examples/random-people-shared-addresses/xampl-gen.rb +36 -0
  19. data/examples/random-people-shared-addresses/xml/people.xml +14 -0
  20. data/examples/random-people/Makefile +16 -0
  21. data/examples/random-people/batch-load-users.rb +61 -0
  22. data/examples/random-people/optimise.rb +16 -0
  23. data/examples/random-people/people.rb +22 -0
  24. data/examples/random-people/query.rb +73 -0
  25. data/examples/random-people/query2.rb +73 -0
  26. data/examples/random-people/random-names.csv +10000 -0
  27. data/examples/random-people/rawtc.rb +91 -0
  28. data/examples/random-people/settings.rb +3 -0
  29. data/examples/random-people/what-to-query-on.rb +80 -0
  30. data/examples/random-people/xampl-gen.rb +36 -0
  31. data/examples/random-people/xml/people.xml +11 -0
  32. data/examples/read-testing/Makefile +10 -0
  33. data/examples/read-testing/load.rb +65 -0
  34. data/examples/read-testing/read.rb +51 -0
  35. data/examples/read-testing/rrr.rb +87 -0
  36. data/examples/read-testing/settings.rb +2 -0
  37. data/examples/read-testing/xampl-gen.rb +36 -0
  38. data/examples/read-testing/xml/text.xml +8 -0
  39. data/examples/tokyo-cabinet-experimental/expt-query.rb +42 -0
  40. data/examples/tokyo-cabinet-experimental/expt-query2.rb +42 -0
  41. data/examples/tokyo-cabinet-experimental/expt-query3.rb +41 -0
  42. data/examples/tokyo-cabinet-experimental/expt-reader.rb +32 -0
  43. data/examples/tokyo-cabinet-experimental/expt.rb +61 -0
  44. data/examples/tokyo-cabinet-experimental/xampl-gen.rb +36 -0
  45. data/examples/tokyo-cabinet-experimental/xml/tcx.xml +6 -0
  46. data/lib/xampl-generator.rb +3 -0
  47. data/lib/xampl.rb +3 -0
  48. data/lib/xamplr-generator.rb +10 -0
  49. data/lib/xamplr.rb +37 -0
  50. data/lib/xamplr/README-POSSIBLE-PROBLEMS +5 -0
  51. data/lib/xamplr/TODO +1 -0
  52. data/lib/xamplr/exceptions.rb +97 -0
  53. data/lib/xamplr/from-xml-orig.rb +350 -0
  54. data/lib/xamplr/from-xml.rb +439 -0
  55. data/lib/xamplr/gen-elements.xml +6230 -0
  56. data/lib/xamplr/gen.elements.xml +108 -0
  57. data/lib/xamplr/generate-elements.rb +15 -0
  58. data/lib/xamplr/generator.rb +5 -0
  59. data/lib/xamplr/graphml-out.rb +470 -0
  60. data/lib/xamplr/handwritten/example.rb +698 -0
  61. data/lib/xamplr/handwritten/hand-example.rb +533 -0
  62. data/lib/xamplr/handwritten/test-handwritten.rb +873 -0
  63. data/lib/xamplr/indexed-array.rb +115 -0
  64. data/lib/xamplr/mixins.rb +397 -0
  65. data/lib/xamplr/my.gen.elements.xml +461 -0
  66. data/lib/xamplr/notifications.rb +57 -0
  67. data/lib/xamplr/obsolete/fsdb.rb +62 -0
  68. data/lib/xamplr/persist-to-xml.rb +249 -0
  69. data/lib/xamplr/persistence.rb +522 -0
  70. data/lib/xamplr/persistence.rb.more_thread_safe +771 -0
  71. data/lib/xamplr/persistence.rb.partially_thread_safe +763 -0
  72. data/lib/xamplr/persister.rb +310 -0
  73. data/lib/xamplr/persisters/caches.rb +186 -0
  74. data/lib/xamplr/persisters/caching.rb +172 -0
  75. data/lib/xamplr/persisters/filesystem.rb +60 -0
  76. data/lib/xamplr/persisters/in-memory.rb +180 -0
  77. data/lib/xamplr/persisters/simple.rb +59 -0
  78. data/lib/xamplr/persisters/tokyo-cabinet.rb +641 -0
  79. data/lib/xamplr/simpleTemplate/danger.rx +4 -0
  80. data/lib/xamplr/simpleTemplate/obsolete/input-c.r4 +35 -0
  81. data/lib/xamplr/simpleTemplate/obsolete/play.r6.txt +12 -0
  82. data/lib/xamplr/simpleTemplate/obsolete/play_more.r6.txt +20 -0
  83. data/lib/xamplr/simpleTemplate/obsolete/test001.r5 +8 -0
  84. data/lib/xamplr/simpleTemplate/obsolete/test002.r5 +13 -0
  85. data/lib/xamplr/simpleTemplate/obsolete/test003.r5 +37 -0
  86. data/lib/xamplr/simpleTemplate/old/r6.000.rb +122 -0
  87. data/lib/xamplr/simpleTemplate/old/r6.001.rb +145 -0
  88. data/lib/xamplr/simpleTemplate/play.r6 +12 -0
  89. data/lib/xamplr/simpleTemplate/play_more.r6 +20 -0
  90. data/lib/xamplr/simpleTemplate/play_noblanks.r6 +21 -0
  91. data/lib/xamplr/simpleTemplate/playq.r6 +16 -0
  92. data/lib/xamplr/simpleTemplate/r6.rb +87 -0
  93. data/lib/xamplr/simpleTemplate/simple-template.rb +75 -0
  94. data/lib/xamplr/templates/child.template +47 -0
  95. data/lib/xamplr/templates/child_indexed.template +89 -0
  96. data/lib/xamplr/templates/child_modules.template +5 -0
  97. data/lib/xamplr/templates/element_classes.template +11 -0
  98. data/lib/xamplr/templates/element_data.template +282 -0
  99. data/lib/xamplr/templates/element_empty.template +285 -0
  100. data/lib/xamplr/templates/element_mixed.template +277 -0
  101. data/lib/xamplr/templates/element_simple.template +276 -0
  102. data/lib/xamplr/templates/package.template +26 -0
  103. data/lib/xamplr/test-support/Makefile +47 -0
  104. data/lib/xamplr/test-support/bench-cache.rb +80 -0
  105. data/lib/xamplr/test-support/bench-script.rb +21 -0
  106. data/lib/xamplr/test-support/bench.rb +116 -0
  107. data/lib/xamplr/test-support/bench2.rb +132 -0
  108. data/lib/xamplr/test-support/test-cache.rb +147 -0
  109. data/lib/xamplr/test-support/test-data/binding.xml +7 -0
  110. data/lib/xamplr/test-support/test-data/example.xml +14 -0
  111. data/lib/xamplr/test-support/test-data/internationalization-utf8.txt +1 -0
  112. data/lib/xamplr/test-support/test-data/labels.xml +37 -0
  113. data/lib/xamplr/test-support/test-data/labels001.xml +38 -0
  114. data/lib/xamplr/test-support/test-deep-change.rb +135 -0
  115. data/lib/xamplr/test-support/test-elements.rb +109 -0
  116. data/lib/xamplr/test-support/test-indexed-array.rb +169 -0
  117. data/lib/xamplr/test-support/test-misc.rb +73 -0
  118. data/lib/xamplr/test-support/test-names.rb +67 -0
  119. data/lib/xamplr/test-support/test-rollback.rb +106 -0
  120. data/lib/xamplr/test-support/test.rb +1504 -0
  121. data/lib/xamplr/to-ruby.rb +220 -0
  122. data/lib/xamplr/to-xml.rb +158 -0
  123. data/lib/xamplr/version.rb +67 -0
  124. data/lib/xamplr/visitor.rb +140 -0
  125. data/lib/xamplr/visitors.rb +573 -0
  126. data/lib/xamplr/xampl-generator.rb +533 -0
  127. data/lib/xamplr/xampl-hand-generated.rb +1535 -0
  128. data/lib/xamplr/xampl-module.rb +36 -0
  129. data/lib/xamplr/xampl-object-internals.rb +6 -0
  130. data/lib/xamplr/xampl-object.rb +202 -0
  131. data/lib/xamplr/xampl-persisted-object.rb +122 -0
  132. data/lib/xamplr/xml-text.rb +117 -0
  133. data/lib/xamplr/xml/document.xml +7 -0
  134. data/lib/xamplr/xml/elements.xml +101 -0
  135. data/lib/xamplr/xml/elements000.xml +73 -0
  136. data/lib/xamplr/xml/example.xml +23 -0
  137. data/lib/xamplr/xml/options.xml +12 -0
  138. data/lib/xamplr/xml/uche.xml +38 -0
  139. data/lib/xamplr/yEd-sample.graphml +300 -0
  140. data/test/test_helper.rb +10 -0
  141. data/test/xamplr_test.rb +7 -0
  142. metadata +245 -0
@@ -0,0 +1,771 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sync'
4
+
5
+ module Xampl
6
+
7
+ #@@persister = nil
8
+ @@known_persisters = {}
9
+ @@persister_kinds = {}
10
+
11
+ def Xampl.persister
12
+ Thread.current[:persister]
13
+ end
14
+
15
+ def Xampl.block_future_changes(on=true)
16
+ Thread.current[:persister].block_changes = on if Thread.current[:persister]
17
+ end
18
+
19
+ def Xampl.auto_persistence(on=true)
20
+ Thread.current[:persister].automatic = on if Thread.current[:persister]
21
+ end
22
+
23
+ def Xampl.register_persister_kind(klass)
24
+ @@persister_kinds[klass.kind] = klass
25
+ end
26
+
27
+ def Xampl.disable_all_persisters
28
+ Thread.current[:persister] = nil
29
+ @@known_persisters = {}
30
+ end
31
+
32
+ def Xampl.disable_persister
33
+ Thread.current[:persister] = nil
34
+ end
35
+
36
+ @@default_persister_kind = :simple
37
+ @@default_persister_format = :xml_format
38
+
39
+ def Xampl.default_persister_kind
40
+ @@default_persister_kind
41
+ end
42
+ def Xampl.set_default_persister_kind(kind)
43
+ @@default_persister_kind = kind
44
+ puts "SET KIND format: #{@@default_persister_format}, kind: #{@@default_persister_kind}"
45
+ end
46
+
47
+ def Xampl.default_persister_format
48
+ @@default_persister_format
49
+ end
50
+ def Xampl.set_default_persister_format(format)
51
+ @@default_persister_format = format
52
+ puts "SET FORMAT format: #{@@default_persister_format}, kind: #{@@default_persister_kind}"
53
+ end
54
+
55
+ @@xampl_lock = Sync.new
56
+
57
+ def Xampl.enable_persister(name, kind=nil, format=nil)
58
+ initial_persister = nil
59
+
60
+ @@xampl_lock.synchronize(:EX) do
61
+ initial_persister = Thread.current[:persister]
62
+ kind = kind || @@default_persister_kind
63
+ format = format || @@default_persister_format
64
+ Thread.current[:persister] = @@known_persisters[name]
65
+
66
+ if Thread.current[:persister] then
67
+ if kind and kind != Thread.current[:persister].kind then
68
+ raise IncompatiblePersisterRequest.new(Thread.current[:persister], "kind", kind, Thread.current[:persister].kind)
69
+ end
70
+ if format and format != Thread.current[:persister].format then
71
+ raise IncompatiblePersisterRequest.new(Thread.current[:persister], "format", format, Thread.current[:persister].format)
72
+ end
73
+ end
74
+
75
+ unless Thread.current[:persister] then
76
+ # puts "CREATE PERSISTER #{name}, format: #{format}, kind: #{kind}"
77
+ Thread.current[:persister] = @@persister_kinds[kind].new(name, format)
78
+ if(nil != name) then
79
+ @@known_persisters[name] = Thread.current[:persister]
80
+ end
81
+ end
82
+ end
83
+
84
+ return initial_persister
85
+ end
86
+
87
+ def Xampl.print_known_persisters
88
+ puts "Known Persisters:: --------------------------"
89
+ @@known_persisters.each { | n, k |
90
+ puts " #{n} #{k}"
91
+ }
92
+ puts "---------------------------------------------"
93
+ end
94
+
95
+ def Xampl.flush_persister_caches
96
+ Xampl.print_known_persisters
97
+ @@known_persisters.delete(Thread.current[:persister].name)
98
+ Xampl.print_known_persisters
99
+ end
100
+
101
+ def Xampl.drop_all_persisters
102
+ puts "Drop All Persisters:: --------------------------"
103
+ @@known_persisters.each { | n, k |
104
+ puts " #{n} #{k}"
105
+ }
106
+ puts "---------------------------------------------"
107
+ @@known_persisters = {}
108
+ GC.start
109
+ GC.start
110
+ GC.start
111
+ end
112
+
113
+ def Xampl.drop_persister(name)
114
+ Xampl.print_known_persisters
115
+ @@known_persisters.delete(name)
116
+ Xampl.print_known_persisters
117
+ end
118
+
119
+ def Xampl.transaction(thing, kind=nil, automatic=true, format=nil, &block)
120
+ if String === thing then
121
+ name = thing
122
+ elsif XamplObject === thing then
123
+ name = thing.persister.name
124
+ else
125
+ raise XamplException.new("can't base a transaction on a #{thing.class.name} (#{thing})")
126
+ end
127
+
128
+ if block_given? then
129
+ @@xampl_lock.synchronize(:EX) do
130
+ initial_persister = Xampl.enable_persister(name, kind, format)
131
+ Thread.current[:persister].lock.synchronize(:EX) do
132
+ rollback = true
133
+ exception = nil
134
+ original_automatic = Thread.current[:persister].automatic
135
+ begin
136
+ #TODO -- impose some rules on nested transactions/enable_persisters??
137
+ Xampl.auto_persistence(automatic)
138
+ result = yield
139
+ Xampl.block_future_changes(true)
140
+ Xampl.sync
141
+ rollback = false
142
+ return result
143
+ rescue => e
144
+ exception = e
145
+ ensure
146
+ Xampl.block_future_changes(false)
147
+ Xampl.auto_persistence(original_automatic)
148
+ if rollback then
149
+ if exception then
150
+ puts "ROLLBACK(#{__LINE__}):: #{exception}" if rollback
151
+ print exception.backtrace.join("\n") if rollback
152
+ else
153
+ puts "ROLLBACK(#{__LINE__}):: UNKNOWN CAUSE" if rollback
154
+ end
155
+ end
156
+ Xampl.rollback if rollback
157
+ Thread.current[:persister] = initial_persister
158
+ end
159
+ end
160
+ end # sync xampl_lock
161
+ end
162
+ end
163
+
164
+ def Xampl.read_only_transaction(thing, kind=nil, automatic=true, format=nil, &block)
165
+ if String === thing then
166
+ name = thing
167
+ elsif XamplObject === thing then
168
+ name = thing.persister.name
169
+ else
170
+ raise XamplException.new("can't base a transaction on a #{thing.class.name} (#{thing})")
171
+ end
172
+
173
+ target_persister = nil
174
+ if block_given? then
175
+ @@xampl_lock.synchronize(:SH) do
176
+ initial_persister = Xampl.enable_persister(name, kind, format)
177
+ Thread.current[:persister].lock.synchronize(:EX) do
178
+ target_persister = Thread.current[:persister]
179
+
180
+ rollback = true
181
+ original_automatic = Thread.current[:persister].automatic
182
+ @changed ||= nil
183
+ original_changed = @changed
184
+ @changed = {}
185
+ begin
186
+ Xampl.auto_persistence(false)
187
+ #Xampl.block_future_changes(true)
188
+
189
+ yield
190
+ rollback = false
191
+ ensure
192
+ Xampl.auto_persistence(original_automatic)
193
+ #Xampl.block_future_changes(false)
194
+
195
+ if 0 == @changed.size then
196
+ @changed = original_changed
197
+
198
+ puts "ROLLBACK(#{__LINE__})" if rollback
199
+ Xampl.rollback if rollback
200
+ Thread.current[:persister] = initial_persister
201
+ else
202
+ puts "CHANGED COUNT: #{@changed.size}"
203
+ @changed = original_changed
204
+
205
+ puts "ROLLBACK(#{__LINE__})" if rollback
206
+ Xampl.rollback
207
+
208
+ Thread.current[:persister] = initial_persister
209
+
210
+ raise BlockedChange.new(target_persister)
211
+ end
212
+ end
213
+ end
214
+ end # sync xampl_lock
215
+ end
216
+ end
217
+
218
+ def Xampl.read_only(target_persister)
219
+ name = target_persister.name
220
+
221
+ if block_given? then
222
+ @@xampl_lock.synchronize(:SH) do
223
+ initial_persister = Xampl.enable_persister(name, target_persister.kind, target_persister.format)
224
+ Thread.current[:persister].lock.synchronize(:EX) do
225
+ rollback = true
226
+ original_automatic = Thread.current[:persister].automatic
227
+ original_changed = @changed
228
+ @changed = {}
229
+ begin
230
+ Xampl.auto_persistence(false)
231
+ #Xampl.block_future_changes(true)
232
+
233
+ yield
234
+ rollback = false
235
+ ensure
236
+ #### Xampl.auto_persistence(original_automatic)
237
+ #### #Xampl.block_future_changes(false)
238
+ ####
239
+ #### if 0 < @changed.size then
240
+ #### puts "CHANGED COUNT: #{@changed.size}"
241
+ #### raise BlockedChange.new(target_persister)
242
+ #### end
243
+ ####
244
+ #### @changed = original_changed
245
+ ####
246
+ #### puts "ROLLBACK(#{__LINE__})" if rollback
247
+ #### Xampl.rollback if rollback
248
+ #### Thread.current[:persister] = initial_persister
249
+
250
+ Xampl.auto_persistence(original_automatic)
251
+ #Xampl.block_future_changes(false)
252
+
253
+ if 0 == @changed.size then
254
+ @changed = original_changed
255
+
256
+ puts "ROLLBACK(#{__LINE__})" if rollback
257
+ Xampl.rollback if rollback
258
+ Thread.current[:persister] = initial_persister
259
+ else
260
+ puts "CHANGED COUNT: #{@changed.size}"
261
+ @changed = original_changed
262
+
263
+ puts "ROLLBACK(#{__LINE__})" if rollback
264
+ Xampl.rollback
265
+
266
+ Thread.current[:persister] = initial_persister
267
+
268
+ raise BlockedChange.new(target_persister)
269
+ end
270
+ end
271
+ end
272
+
273
+ end # sync xampl_lock
274
+ end
275
+ end
276
+
277
+ def Xampl.introduce_to_persister(xampl)
278
+ Thread.current[:persister].introduce(xampl) if Thread.current[:persister]
279
+ end
280
+
281
+ def Xampl.count_changed
282
+ Thread.current[:persister].count_changed if Thread.current[:persister]
283
+ end
284
+
285
+ def Xampl.print_stats
286
+ Thread.current[:persister].print_stats if Thread.current[:persister]
287
+ end
288
+
289
+ def Xampl.auto_cache(xampl)
290
+ if (nil == xampl.persister) and Thread.current[:persister] and Thread.current[:persister].automatic then
291
+ xampl.persister = Thread.current[:persister]
292
+ end
293
+ if xampl.persister and xampl.persister.automatic then
294
+ xampl.persister.cache(xampl)
295
+ end
296
+ end
297
+
298
+ def Xampl.auto_uncache(xampl)
299
+ if xampl.persister and xampl.persister.automatic then
300
+ xampl.persister.uncache(xampl)
301
+ end
302
+ end
303
+
304
+ def Xampl.clear_cache
305
+ Thread.current[:persister].clear_cache if Thread.current[:persister]
306
+ end
307
+
308
+ def Xampl.sync
309
+ #raise XamplException.new(:live_across_rollback) if @@persister.rolled_back
310
+ Thread.current[:persister].sync if Thread.current[:persister]
311
+ end
312
+
313
+ def Xampl.sync_all
314
+ @@known_persisters.each{ | name, persister |
315
+ persister.sync
316
+ }
317
+ end
318
+
319
+ def Xampl.rollback(persister=Thread.current[:persister])
320
+ raise NoActivePersister unless persister
321
+ persister.rollback_cleanup
322
+ end
323
+
324
+ def Xampl.rollback_all
325
+ @@known_persisters.values.each{ | persister |
326
+ persister.rollback
327
+ }
328
+ end
329
+
330
+ def Xampl.lazy_load(xampl)
331
+ @@xampl_lock.synchronize(:SH) do
332
+ Thread.current[:persister].lock.synchronize(:EX) do
333
+ pid = xampl.get_the_index
334
+ if xampl and pid and Thread.current[:persister] then
335
+ Thread.current[:persister].lazy_load(xampl, xampl.class, pid) if xampl and pid and Thread.current[:persister]
336
+ xampl.load_needed = false
337
+ else
338
+ puts "XAMPL.LAZY_LOAD -- REFUSED"
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ def Xampl.lookup(klass, pid)
345
+ Thread.current[:persister].lookup(klass, pid) if Thread.current[:persister]
346
+ end
347
+
348
+ def Xampl.find_known(klass, pid)
349
+ xampl, ignore = Thread.current[:persister].find_known(klass, pid) if Thread.current[:persister]
350
+ return xampl
351
+ end
352
+
353
+ def Xampl.write_to_cache(xampl)
354
+ Thread.current[:persister].write_to_cache(xampl)
355
+ end
356
+
357
+ def Xampl.cache(xampl)
358
+ Thread.current[:persister].cache(xampl)
359
+ end
360
+
361
+ def Xampl.lookup_in_map(map, klass, pid)
362
+ return nil if nil == pid
363
+
364
+ module_name = klass.module_name
365
+ tag = klass.tag
366
+
367
+ tag_map = map[module_name]
368
+ return nil if nil == tag_map
369
+
370
+ pid_map = tag_map[tag]
371
+ return nil if nil == pid_map
372
+
373
+ return pid_map[pid]
374
+ end
375
+
376
+ def Xampl.store_in_map(map, xampl)
377
+ module_name = xampl.module_name
378
+ tag = xampl.tag
379
+ pid = xampl.get_the_index
380
+
381
+ if nil == pid then
382
+ return false
383
+ end
384
+
385
+ if block_given? then
386
+ data = yield
387
+ else
388
+ data = xampl
389
+ end
390
+
391
+ tag_map = map[module_name]
392
+ if nil == tag_map then
393
+ tag_map = {}
394
+ map[module_name] = tag_map
395
+ end
396
+
397
+ pid_map = tag_map[tag]
398
+ if nil == pid_map then
399
+ pid_map = {}
400
+ tag_map[tag] = pid_map
401
+ end
402
+
403
+ pid_map[pid] = data
404
+
405
+ return true
406
+ end
407
+
408
+ def Xampl.store_in_cache(map, xampl, container)
409
+ module_name = xampl.module_name
410
+ tag = xampl.tag
411
+ pid = xampl.get_the_index
412
+
413
+ if nil == pid then
414
+ return false
415
+ end
416
+
417
+ if block_given? then
418
+ data = yield
419
+ else
420
+ data = xampl
421
+ end
422
+
423
+ tag_map = map[module_name]
424
+ if nil == tag_map then
425
+ tag_map = {}
426
+ map[module_name] = tag_map
427
+ end
428
+
429
+ pid_map = tag_map[tag]
430
+ if nil == pid_map then
431
+ pid_map = container.fresh_cache
432
+ tag_map[tag] = pid_map
433
+ end
434
+
435
+ pid_map[pid] = data
436
+
437
+ return true
438
+ end
439
+
440
+ def Xampl.remove_from_map(map, xampl)
441
+ pid = xampl.get_the_index
442
+ return nil unless pid
443
+
444
+ tag_map = map[xampl.module_name]
445
+ return nil unless tag_map
446
+
447
+ pid_map = tag_map[xampl.tag]
448
+ return nil unless pid_map
449
+
450
+ return pid_map.delete(pid)
451
+ end
452
+
453
+ class Persister
454
+ attr_accessor :name,
455
+ :automatic,
456
+ :block_changes,
457
+ :read_count, :total_read_count,
458
+ :write_count, :total_write_count,
459
+ :total_sync_count, :total_rollback_count,
460
+ :cache_hits, :total_cache_hits,
461
+ :last_write_count,
462
+ :rolled_back
463
+ attr_reader :syncing, :format, :lock
464
+
465
+ def initialize(name=nil, format=nil)
466
+ @name = name
467
+ @format = format
468
+ @automatic = false
469
+ @changed = {}
470
+ @cache_hits = 0
471
+ @total_cache_hits = 0
472
+ @read_count = 0
473
+ @total_read_count = 0
474
+ @write_count = 0
475
+ @total_write_count = 0
476
+ @last_write_count = 0
477
+ @total_sync_count = 0
478
+ @total_rollback_count = 0
479
+ @rolled_back = false
480
+ @syncing = false
481
+
482
+ @lock = Sync.new
483
+
484
+ @busy_count = 0
485
+ end
486
+
487
+ def busy(yes)
488
+ if yes then
489
+ @busy_count += 1
490
+ elsif 0 < @busy_count then
491
+ @busy_count -= 1
492
+ end
493
+ end
494
+
495
+ def is_busy
496
+ return 0 < @busy_count
497
+ end
498
+
499
+ def introduce(xampl)
500
+ if xampl.introduce_persister(self) then
501
+ cache(xampl)
502
+ end
503
+ has_changed(xampl) if xampl.is_changed
504
+ end
505
+
506
+ def has_changed(xampl)
507
+ #raise XamplException.new(:live_across_rollback) if @rolled_back
508
+ # puts "!!!! has_changed #{xampl} #{xampl.get_the_index} -- persist required: #{xampl.persist_required}"
509
+ if xampl.persist_required && xampl.is_changed then
510
+ unless self == xampl.persister
511
+ raise MixedPersisters.new(xampl.persister, self)
512
+ end
513
+ @changed[xampl] = xampl
514
+ # puts "!!!! change recorded ==> #{@changed.size}/#{count_changed} #{@changed.object_id} !!!!"
515
+ # @changed.each{ | thing, ignore |
516
+ # puts " changed: #{thing}, index: #{thing.get_the_index}, changed: #{thing.is_changed}"
517
+ # }
518
+ end
519
+ end
520
+
521
+ def has_not_changed(xampl)
522
+ # puts "!!!! has_not_changed #{xampl} #{xampl.get_the_index} -- in @changed: #{nil != @changed[xampl]}"
523
+ @changed.delete(xampl) if xampl
524
+ end
525
+
526
+ def count_changed
527
+ # @changed.each{ | thing, ignore |
528
+ # puts "changed: #{thing}, index: #{thing.get_the_index}"
529
+ # }
530
+ return @changed.size
531
+ end
532
+
533
+ def cache(xampl)
534
+ raise XamplException.new(:unimplemented)
535
+ end
536
+
537
+ def uncache(xampl)
538
+ raise XamplException.new(:unimplemented)
539
+ end
540
+
541
+ def clear_cache
542
+ raise XamplException.new(:unimplemented)
543
+ end
544
+
545
+ def Persister.replace(old_xampl, new_xampl)
546
+ pid = old_xampl.get_the_index
547
+ if old_xampl.persister != Thread.current[:persister] then
548
+ raise MixedPersisters.new(Thread.current[:persister], old_xampl.persister)
549
+ end
550
+ if new_xampl.persister != Thread.current[:persister] then
551
+ raise MixedPersisters.new(Thread.current[:persister], new_xampl.persister)
552
+ end
553
+
554
+ new_xampl.note_replacing(old_xampl)
555
+
556
+ unless old_xampl.load_needed then
557
+ Xampl.log.warn("Replacing live xampl: #{old_xampl} pid: #{pid}")
558
+ Thread.current[:persister].uncache(old_xampl)
559
+ old_xampl.invalidate
560
+ end
561
+ new_xampl.pid = nil
562
+ new_xampl.pid = pid
563
+ Thread.current[:persister].introduce(new_xampl)
564
+ end
565
+
566
+ def represent(xampl)
567
+ case @format
568
+ when nil, :xml_format then
569
+ return xampl.persist
570
+ when :ruby_format then
571
+ return xampl.to_ruby
572
+ end
573
+ end
574
+
575
+ def realise(representation, target=nil)
576
+ # Normally we'd expect to see the representation in the @format format, but
577
+ # that isn't necessarily the case. Try to work out what the format might be...
578
+
579
+ if representation =~ /^</ then
580
+ return XamplObject.realise_from_xml_string(representation, target)
581
+ else
582
+ XamplObject.from_ruby(representation, target)
583
+ end
584
+ end
585
+
586
+ def write(xampl)
587
+ raise XamplException.new(:unimplemented)
588
+ end
589
+
590
+ def read(klass, pid, target=nil)
591
+ raise XamplException.new(:unimplemented)
592
+ end
593
+
594
+ def lookup(klass, pid)
595
+ #raise XamplException.new(:live_across_rollback) if @rolled_back
596
+
597
+ # puts "LOOKUP:: klass: #{klass} pid: #{pid}"
598
+
599
+ begin
600
+ busy(true)
601
+ xampl = read(klass, pid)
602
+ ensure
603
+ busy(false)
604
+ end
605
+
606
+ return xampl
607
+ end
608
+
609
+ def find_known(klass, pid)
610
+ #raise XamplException.new(:live_across_rollback) if @rolled_back
611
+
612
+ xampl = read_from_cache(klass, pid, nil)
613
+
614
+ return xampl
615
+ end
616
+
617
+ def lazy_load(target, klass, pid)
618
+ # puts "LAZY_LOAD:: klass: #{klass} pid: #{pid} target: #{target}"
619
+
620
+ xampl = read(klass, pid, target)
621
+
622
+ # puts " LAZY_LOAD --> #{xampl}"
623
+
624
+ return xampl
625
+ end
626
+
627
+ def put_changed(msg="")
628
+ puts "Changed::#{msg}:"
629
+ @changed.each { | xampl, ignore | puts " #{xampl.tag} #{xampl.get_the_index}" }
630
+ end
631
+
632
+ def do_sync_write
633
+ unchanged_in_changed_list = 0
634
+ # puts "DO SYNC WRITE:: changed: #{@changed.size}, #{@changed.object_id}"
635
+ @changed.each { | xampl, ignore |
636
+ # puts " WRITE: #{xampl}, index: #{xampl.get_the_index}, changed: #{xampl.is_changed}"
637
+
638
+ unchanged_in_changed_list += 1 unless xampl.is_changed
639
+ write(xampl) unless xampl.kind_of?(InvalidXampl)
640
+ }
641
+ end
642
+
643
+ def sync
644
+ #raise XamplException.new(:live_across_rollback) if @rolled_back
645
+ begin
646
+ #puts "SYNC"
647
+ #puts "SYNC"
648
+ #puts "SYNC changed: #{@changed.size}"
649
+ #@changed.each do | key, value |
650
+ # #puts "key: #{key.class.name}, value: #{value.class.name}"
651
+ # puts key.to_xml
652
+ #end
653
+ #puts "SYNC"
654
+ #puts "SYNC"
655
+ busy(true)
656
+ @syncing = true
657
+
658
+ do_sync_write
659
+
660
+ @changed = {}
661
+
662
+ @total_read_count = @total_read_count + @read_count
663
+ @total_write_count = @total_write_count + @write_count
664
+ @total_cache_hits = @total_cache_hits + @cache_hits
665
+ @total_sync_count = @total_sync_count + 1
666
+
667
+ @read_count = 0
668
+ @last_write_count = @write_count
669
+ @write_count = 0
670
+
671
+ self.sync_done()
672
+
673
+ return @last_write_count
674
+ ensure
675
+ busy(false)
676
+ @syncing = false
677
+ end
678
+ end
679
+
680
+ def sync_done
681
+ raise XamplException.new(:unimplemented)
682
+ end
683
+
684
+ def rollback
685
+ begin
686
+ busy(true)
687
+
688
+ return Xampl.rollback(self)
689
+ ensure
690
+ busy(false)
691
+ end
692
+ end
693
+
694
+ def rollback_cleanup
695
+ @changed = {}
696
+ end
697
+
698
+ def print_stats
699
+ printf("SYNC:: TOTAL cache_hits: %d, reads: %d, writes: %d\n",
700
+ @total_cache_hits, @total_read_count, @total_write_count)
701
+ printf(" cache_hits: %d, reads: %d, last writes: %d\n",
702
+ @cache_hits, @read_count, @last_write_count)
703
+ printf(" syncs: %d\n", @total_sync_count)
704
+ printf(" changed count: %d (%d)\n", count_changed, @changed.size)
705
+ @changed.each{ | thing, ignore |
706
+ if thing.is_changed then
707
+ puts " changed: #{thing}, index: #{thing.get_the_index}"
708
+ else
709
+ puts " UNCHANGED: #{thing}, index: #{thing.get_the_index} <<<<<<<<<<<<<<<<<<< BAD!"
710
+ end
711
+ }
712
+ end
713
+ end
714
+
715
+ class NoActivePersister < Exception
716
+ def message
717
+ "No Persister is active"
718
+ end
719
+ end
720
+
721
+ class BlockedChange < Exception
722
+ attr_reader :xampl
723
+
724
+ def initialize(xampl=nil)
725
+ @xampl = xampl
726
+ end
727
+
728
+ def message
729
+ "attempt to change #{@xampl}, pid: #{@xampl.get_the_index}, oid: #{@xampl.object_id} when changes are blocked"
730
+ end
731
+ end
732
+
733
+ class UnmanagedChange < Exception
734
+ attr_reader :xampl
735
+
736
+ def initialize(xampl=nil)
737
+ @xampl = xampl
738
+ end
739
+
740
+ def message
741
+ "attempt to change #{@xampl}, pid: #{@xampl.get_the_index}, oid: #{@xampl.object_id} outside of its persister's management"
742
+ end
743
+ end
744
+
745
+ class IncompatiblePersisterRequest < Exception
746
+ attr_reader :msg
747
+ def initialize(persister, feature_name, requested_feature_value, actual_feature_value)
748
+ @msg = "persister #{persister.name}:: requested feature: #{feature_name} #{requested_feature_value}, actual: #{actual_feature_value}"
749
+ end
750
+
751
+ def message
752
+ @msg
753
+ end
754
+ end
755
+
756
+ class MixedPersisters < Exception
757
+ attr_reader :msg
758
+ def initialize(active, local)
759
+ @msg = "mixed persisters:: active #{active.name}, local: #{local.name}"
760
+ end
761
+
762
+ def message
763
+ @msg
764
+ end
765
+ end
766
+
767
+ require "persister/simple"
768
+ require "persister/in-memory"
769
+ require "persister/filesystem"
770
+ end
771
+