fsdb 0.5 → 0.6.0

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.
Files changed (176) hide show
  1. data/{RELEASE-NOTES → History.txt} +6 -0
  2. data/{README → README.txt} +26 -17
  3. data/examples/flat.rb +146 -0
  4. data/examples/fsdb-example.rb +28 -0
  5. data/examples/rbformat.rb +17 -0
  6. data/examples/yaml2.rb +29 -0
  7. data/junk/OLDRakefile +98 -0
  8. data/junk/OLDRakefile2 +55 -0
  9. data/junk/check-cache.rb +18 -0
  10. data/junk/create-lock.rb +25 -0
  11. data/junk/doc/old-api/classes/FSDB.html +139 -0
  12. data/junk/doc/old-api/classes/FSDB/Database.html +953 -0
  13. data/junk/doc/old-api/classes/FSDB/Database.src/M000029.html +16 -0
  14. data/junk/doc/old-api/classes/FSDB/Database.src/M000030.html +16 -0
  15. data/junk/doc/old-api/classes/FSDB/Database.src/M000031.html +16 -0
  16. data/junk/doc/old-api/classes/FSDB/Database.src/M000032.html +16 -0
  17. data/junk/doc/old-api/classes/FSDB/Database.src/M000033.html +33 -0
  18. data/junk/doc/old-api/classes/FSDB/Database.src/M000034.html +18 -0
  19. data/junk/doc/old-api/classes/FSDB/Database.src/M000035.html +22 -0
  20. data/junk/doc/old-api/classes/FSDB/Database.src/M000036.html +16 -0
  21. data/junk/doc/old-api/classes/FSDB/Database.src/M000037.html +22 -0
  22. data/junk/doc/old-api/classes/FSDB/Database.src/M000038.html +43 -0
  23. data/junk/doc/old-api/classes/FSDB/Database.src/M000039.html +25 -0
  24. data/junk/doc/old-api/classes/FSDB/Database.src/M000040.html +43 -0
  25. data/junk/doc/old-api/classes/FSDB/Database.src/M000041.html +23 -0
  26. data/junk/doc/old-api/classes/FSDB/Database.src/M000042.html +22 -0
  27. data/junk/doc/old-api/classes/FSDB/Database.src/M000043.html +16 -0
  28. data/junk/doc/old-api/classes/FSDB/Database.src/M000044.html +16 -0
  29. data/junk/doc/old-api/classes/FSDB/Database.src/M000045.html +18 -0
  30. data/junk/doc/old-api/classes/FSDB/Database.src/M000046.html +18 -0
  31. data/junk/doc/old-api/classes/FSDB/Database.src/M000047.html +18 -0
  32. data/junk/doc/old-api/classes/FSDB/Database.src/M000048.html +16 -0
  33. data/junk/doc/old-api/classes/FSDB/Database.src/M000049.html +71 -0
  34. data/junk/doc/old-api/classes/FSDB/Database.src/M000050.html +43 -0
  35. data/junk/doc/old-api/classes/FSDB/Database.src/M000051.html +53 -0
  36. data/junk/doc/old-api/classes/FSDB/Database.src/M000052.html +44 -0
  37. data/junk/doc/old-api/classes/FSDB/Database.src/M000053.html +39 -0
  38. data/junk/doc/old-api/classes/FSDB/Database.src/M000054.html +72 -0
  39. data/junk/doc/old-api/classes/FSDB/Database.src/M000055.html +39 -0
  40. data/junk/doc/old-api/classes/FSDB/Database.src/M000056.html +18 -0
  41. data/junk/doc/old-api/classes/FSDB/Database.src/M000057.html +18 -0
  42. data/junk/doc/old-api/classes/FSDB/Database.src/M000058.html +18 -0
  43. data/junk/doc/old-api/classes/FSDB/Database.src/M000059.html +18 -0
  44. data/junk/doc/old-api/classes/FSDB/Database.src/M000060.html +18 -0
  45. data/junk/doc/old-api/classes/FSDB/Database.src/M000061.html +23 -0
  46. data/junk/doc/old-api/classes/FSDB/Database.src/M000062.html +23 -0
  47. data/junk/doc/old-api/classes/FSDB/Database.src/M000063.html +18 -0
  48. data/junk/doc/old-api/classes/FSDB/Database.src/M000064.html +18 -0
  49. data/junk/doc/old-api/classes/FSDB/Database/AbortedTransaction.html +118 -0
  50. data/junk/doc/old-api/classes/FSDB/Database/CreateFileError.html +120 -0
  51. data/junk/doc/old-api/classes/FSDB/Database/DirIsImmutableError.html +117 -0
  52. data/junk/doc/old-api/classes/FSDB/Database/DirNotEmptyError.html +117 -0
  53. data/junk/doc/old-api/classes/FSDB/Database/FormatError.html +117 -0
  54. data/junk/doc/old-api/classes/FSDB/Database/MissingFileError.html +117 -0
  55. data/junk/doc/old-api/classes/FSDB/Database/MissingObjectError.html +117 -0
  56. data/junk/doc/old-api/classes/FSDB/Database/NotDirError.html +118 -0
  57. data/junk/doc/old-api/classes/FSDB/Database/PathComponentError.html +120 -0
  58. data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.html +148 -0
  59. data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.src/M000005.html +21 -0
  60. data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.src/M000007.html +21 -0
  61. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.html +210 -0
  62. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000006.html +22 -0
  63. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000007.html +22 -0
  64. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000008.html +22 -0
  65. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000009.html +22 -0
  66. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000010.html +22 -0
  67. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000011.html +22 -0
  68. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000012.html +22 -0
  69. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000013.html +22 -0
  70. data/junk/doc/old-api/classes/FSDB/ForkSafely.html +126 -0
  71. data/junk/doc/old-api/classes/FSDB/Modex.html +237 -0
  72. data/junk/doc/old-api/classes/FSDB/Modex.src/M000024.html +21 -0
  73. data/junk/doc/old-api/classes/FSDB/Modex.src/M000025.html +30 -0
  74. data/junk/doc/old-api/classes/FSDB/Modex.src/M000026.html +21 -0
  75. data/junk/doc/old-api/classes/FSDB/Modex.src/M000027.html +30 -0
  76. data/junk/doc/old-api/classes/FSDB/Modex.src/M000028.html +44 -0
  77. data/junk/doc/old-api/classes/FSDB/Modex.src/M000029.html +26 -0
  78. data/junk/doc/old-api/classes/FSDB/Modex.src/M000030.html +48 -0
  79. data/junk/doc/old-api/classes/FSDB/Modex/ForkSafely.html +105 -0
  80. data/junk/doc/old-api/classes/FSDB/Mutex.html +244 -0
  81. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000018.html +19 -0
  82. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000019.html +18 -0
  83. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000020.html +19 -0
  84. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000021.html +18 -0
  85. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000022.html +23 -0
  86. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000023.html +30 -0
  87. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000024.html +26 -0
  88. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000025.html +21 -0
  89. data/junk/doc/old-api/classes/FSDB/Mutex/ForkSafely.html +105 -0
  90. data/junk/doc/old-api/classes/FSDB/PathUtilities.html +257 -0
  91. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000012.html +23 -0
  92. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000013.html +18 -0
  93. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000014.html +23 -0
  94. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000015.html +18 -0
  95. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000016.html +18 -0
  96. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000017.html +22 -0
  97. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000018.html +23 -0
  98. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000019.html +18 -0
  99. data/junk/doc/old-api/classes/FSDB/PathUtilities/InvalidPathError.html +111 -0
  100. data/junk/doc/old-api/classes/File.html +272 -0
  101. data/junk/doc/old-api/classes/File.src/M000001.html +17 -0
  102. data/junk/doc/old-api/classes/File.src/M000002.html +17 -0
  103. data/junk/doc/old-api/classes/File.src/M000003.html +20 -0
  104. data/junk/doc/old-api/classes/File.src/M000004.html +20 -0
  105. data/junk/doc/old-api/classes/File.src/M000005.html +32 -0
  106. data/junk/doc/old-api/classes/File.src/M000006.html +32 -0
  107. data/junk/doc/old-api/created.rid +1 -0
  108. data/junk/doc/old-api/files/README.html +112 -0
  109. data/junk/doc/old-api/files/RELEASE-NOTES.html +233 -0
  110. data/junk/doc/old-api/files/fsdb_txt.html +888 -0
  111. data/junk/doc/old-api/files/lib/fsdb/database_rb.html +115 -0
  112. data/junk/doc/old-api/files/lib/fsdb/file-lock_rb.html +109 -0
  113. data/junk/doc/old-api/files/lib/fsdb/modex_rb.html +121 -0
  114. data/junk/doc/old-api/files/lib/fsdb/mutex_rb.html +108 -0
  115. data/junk/doc/old-api/files/lib/fsdb/util_rb.html +108 -0
  116. data/junk/doc/old-api/fr_class_index.html +47 -0
  117. data/junk/doc/old-api/fr_file_index.html +34 -0
  118. data/junk/doc/old-api/fr_method_index.html +90 -0
  119. data/junk/doc/old-api/index.html +24 -0
  120. data/junk/doc/old-api/rdoc-style.css +208 -0
  121. data/junk/file-lock-nb.rb +15 -0
  122. data/junk/fl.rb +144 -0
  123. data/junk/flock-test.rb +39 -0
  124. data/junk/fsdb.kateproject +47 -0
  125. data/junk/fsdb.prj +196 -0
  126. data/junk/fsdb.sf +46 -0
  127. data/junk/insert-dir.rb +48 -0
  128. data/junk/lock-test-bug.rb +150 -0
  129. data/junk/lock-test-too-simple.rb +136 -0
  130. data/junk/lock-test.rb +151 -0
  131. data/{script → junk}/mkrdoc +0 -0
  132. data/junk/restore-fsdb.rb +37 -0
  133. data/junk/rf.txt +5 -0
  134. data/junk/solaris-bug-fixed.rb +184 -0
  135. data/junk/solaris-bug.rb +182 -0
  136. data/junk/solaris-bug.txt +43 -0
  137. data/junk/sync.rb +327 -0
  138. data/junk/test-file-lock.html +86 -0
  139. data/junk/test-file-lock.rb +84 -0
  140. data/junk/test-processes.rb +131 -0
  141. data/junk/test-threads.rb +113 -0
  142. data/junk/wiki-mutex.rb +108 -0
  143. data/lib/fsdb/database.rb +5 -3
  144. data/lib/fsdb/delegatable.rb +21 -0
  145. data/lib/fsdb/faster-modex.rb +223 -0
  146. data/lib/fsdb/faster-mutex.rb +138 -0
  147. data/lib/fsdb/mutex.rb +4 -1
  148. data/lib/fsdb/persistent.rb +91 -0
  149. data/lib/fsdb/read-write-object.rb +36 -0
  150. data/lib/fsdb/server.rb +44 -0
  151. data/misc/fsdb-blorubu.txt +47 -0
  152. data/misc/mtime-and-file-id.txt +23 -0
  153. data/misc/posixlock.txt +148 -0
  154. data/rakefile +39 -0
  155. data/tasks/ann.rake +80 -0
  156. data/tasks/bones.rake +20 -0
  157. data/tasks/gem.rake +201 -0
  158. data/tasks/git.rake +40 -0
  159. data/tasks/notes.rake +27 -0
  160. data/tasks/post_load.rake +34 -0
  161. data/tasks/rdoc.rake +51 -0
  162. data/tasks/rubyforge.rake +55 -0
  163. data/tasks/setup.rb +292 -0
  164. data/tasks/spec.rake +54 -0
  165. data/tasks/svn.rake +47 -0
  166. data/tasks/test.rake +40 -0
  167. data/tasks/zentest.rake +36 -0
  168. data/test/err.txt +31 -0
  169. data/test/runs.rb +8 -0
  170. data/test/test-file-lock.rb +78 -0
  171. data/test/test-util.rb +1 -0
  172. data/test/trap.rb +31 -0
  173. metadata +198 -35
  174. data/Manifest +0 -36
  175. data/Rakefile +0 -10
  176. data/fsdb.gemspec +0 -113
data/junk/sync.rb ADDED
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless defined? Thread.exclusive
4
+ def Thread.exclusive
5
+ old = Thread.critical
6
+ begin
7
+ Thread.critical = true
8
+ return yield
9
+ ensure
10
+ Thread.critical = old
11
+ end
12
+ end
13
+ end
14
+
15
+ module FSDB
16
+
17
+ # Synchronzer class based on standard sync.rb, which has some problems:
18
+ # - waiters are not a strict queue (try_lock can jump the queue, after
19
+ # which the queue gets *rotated*). Race condition.
20
+ # - doesn't use Thread.exclusive in enough places
21
+ # - no way to make dead threads give up the mutex, which is crucial in a fork
22
+
23
+ # based on standard sync.rb
24
+ module Sync_m
25
+ # lock mode
26
+ UN = :UN
27
+ SH = :SH
28
+ EX = :EX
29
+
30
+ # exceptions
31
+ class Err < StandardError
32
+ def Err.Fail(*opt)
33
+ fail self, sprintf(self::Message, *opt)
34
+ end
35
+
36
+ class UnknownLocker < Err
37
+ Message = "Thread(%s) not locked."
38
+ def UnknownLocker.Fail(th)
39
+ super(th.inspect)
40
+ end
41
+ end
42
+
43
+ class LockModeFailer < Err
44
+ Message = "Unknown lock mode(%s)"
45
+ def LockModeFailer.Fail(mode)
46
+ if mode.id2name
47
+ mode = id2name
48
+ end
49
+ super(mode)
50
+ end
51
+ end
52
+ end
53
+
54
+ def Sync_m.define_aliases(cl)
55
+ cl.module_eval %q{
56
+ alias locked? sync_locked?
57
+ alias shared? sync_shared?
58
+ alias exclusive? sync_exclusive?
59
+ alias lock sync_lock
60
+ alias unlock sync_unlock
61
+ alias try_lock sync_try_lock
62
+ alias synchronize sync_synchronize
63
+ }
64
+ end
65
+
66
+ def Sync_m.append_features(cl)
67
+ super
68
+ unless cl.instance_of?(Module)
69
+ # do nothing for Modules
70
+ # make aliases and include the proper module.
71
+ define_aliases(cl)
72
+ end
73
+ end
74
+
75
+ def Sync_m.extend_object(obj)
76
+ super
77
+ obj.sync_extended
78
+ end
79
+
80
+ def sync_extended
81
+ unless (defined? locked? and
82
+ defined? shared? and
83
+ defined? exclusive? and
84
+ defined? lock and
85
+ defined? unlock and
86
+ defined? try_lock and
87
+ defined? synchronize)
88
+ Sync_m.define_aliases(class<<self;self;end)
89
+ end
90
+ sync_initialize
91
+ end
92
+
93
+ # accessing
94
+ def sync_locked?
95
+ sync_mode != UN
96
+ end
97
+
98
+ def sync_shared?
99
+ sync_mode == SH
100
+ end
101
+
102
+ def sync_exclusive?
103
+ sync_mode == EX
104
+ end
105
+
106
+ # locking methods.
107
+ def sync_try_lock(mode = EX)
108
+ return unlock if sync_mode == UN
109
+
110
+ Thread.critical = true
111
+ ret = sync_try_lock_sub(sync_mode)
112
+ Thread.critical = false
113
+ ret
114
+ end
115
+
116
+ def sync_lock(m = EX)
117
+ return unlock if m == UN
118
+
119
+ until (Thread.critical = true; sync_try_lock_sub(m))
120
+ if sync_sh_locker[Thread.current]
121
+ sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
122
+ sync_sh_locker.delete(Thread.current)
123
+ else
124
+ sync_waiting.push Thread.current
125
+ end
126
+ Thread.stop
127
+ end
128
+ Thread.critical = false
129
+ self
130
+ end
131
+
132
+ def sync_unlock(m = EX)
133
+ Thread.critical = true
134
+ if sync_mode == UN
135
+ Thread.critical = false
136
+ Err::UnknownLocker.Fail(Thread.current)
137
+ end
138
+
139
+ m = sync_mode if m == EX and sync_mode == SH
140
+
141
+ runnable = false
142
+ case m
143
+ when UN
144
+ Thread.critical = false
145
+ Err::UnknownLocker.Fail(Thread.current)
146
+
147
+ when EX
148
+ if sync_ex_locker == Thread.current
149
+ if (self.sync_ex_count = sync_ex_count - 1) == 0
150
+ self.sync_ex_locker = nil
151
+ if sync_sh_locker.include?(Thread.current)
152
+ self.sync_mode = SH
153
+ else
154
+ self.sync_mode = UN
155
+ end
156
+ runnable = true
157
+ end
158
+ else
159
+ Err::UnknownLocker.Fail(Thread.current)
160
+ end
161
+
162
+ when SH
163
+ if (count = sync_sh_locker[Thread.current]).nil?
164
+ Err::UnknownLocker.Fail(Thread.current)
165
+ else
166
+ if (sync_sh_locker[Thread.current] = count - 1) == 0
167
+ sync_sh_locker.delete(Thread.current)
168
+ if sync_sh_locker.empty? and sync_ex_count == 0
169
+ self.sync_mode = UN
170
+ runnable = true
171
+ end
172
+ end
173
+ end
174
+ end
175
+
176
+ if runnable
177
+ if sync_upgrade_waiting.size > 0
178
+ for k, v in sync_upgrade_waiting
179
+ sync_sh_locker[k] = v
180
+ end
181
+ wait = sync_upgrade_waiting
182
+ self.sync_upgrade_waiting = []
183
+ Thread.critical = false
184
+
185
+ for w, v in wait
186
+ w.run
187
+ end
188
+ else
189
+ wait = sync_waiting
190
+ self.sync_waiting = []
191
+ Thread.critical = false
192
+ for w in wait
193
+ w.run
194
+ end
195
+ end
196
+ end
197
+
198
+ Thread.critical = false
199
+ self
200
+ end
201
+
202
+ def sync_synchronize(mode = EX)
203
+ begin
204
+ sync_lock(mode)
205
+ yield
206
+ ensure
207
+ sync_unlock
208
+ end
209
+ end
210
+
211
+ attr :sync_mode, true
212
+
213
+ attr :sync_waiting, true
214
+ attr :sync_upgrade_waiting, true
215
+ attr :sync_sh_locker, true
216
+ attr :sync_ex_locker, true
217
+ attr :sync_ex_count, true
218
+
219
+ private
220
+
221
+ def sync_initialize
222
+ @sync_mode = UN
223
+ @sync_waiting = []
224
+ @sync_upgrade_waiting = []
225
+ @sync_sh_locker = Hash.new
226
+ @sync_ex_locker = nil
227
+ @sync_ex_count = 0
228
+ end
229
+
230
+ def initialize(*args)
231
+ sync_initialize
232
+ super
233
+ end
234
+
235
+ def sync_try_lock_sub(m)
236
+ case m
237
+ when SH
238
+ case sync_mode
239
+ when UN
240
+ self.sync_mode = m
241
+ sync_sh_locker[Thread.current] = 1
242
+ ret = true
243
+ when SH
244
+ count = 0 unless count = sync_sh_locker[Thread.current]
245
+ sync_sh_locker[Thread.current] = count + 1
246
+ ret = true
247
+ when EX
248
+ # in EX mode, lock will upgrade to EX lock
249
+ if sync_ex_locker == Thread.current
250
+ self.sync_ex_count = sync_ex_count + 1
251
+ ret = true
252
+ else
253
+ ret = false
254
+ end
255
+ end
256
+ when EX
257
+ if sync_mode == UN or
258
+ sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
259
+ self.sync_mode = m
260
+ self.sync_ex_locker = Thread.current
261
+ self.sync_ex_count = 1
262
+ ret = true
263
+ elsif sync_mode == EX && sync_ex_locker == Thread.current
264
+ self.sync_ex_count = sync_ex_count + 1
265
+ ret = true
266
+ else
267
+ ret = false
268
+ end
269
+ else
270
+ Thread.critical = false
271
+ Err::LockModeFailer.Fail mode
272
+ end
273
+ return ret
274
+ end
275
+ end
276
+ Synchronizer_m = Sync_m
277
+
278
+ class Sync
279
+ #Sync_m.extend_class self
280
+ include Sync_m
281
+
282
+ def initialize
283
+ super
284
+ end
285
+
286
+ module ForkSafely
287
+ def fork
288
+ super do
289
+ ### ObjectSpace.each_object(Sync) { |m| m.remove_dead_waiters }
290
+ yield
291
+ end
292
+ end
293
+ end
294
+ end
295
+ Synchronizer = Sync
296
+
297
+
298
+ # FSDB users who fork should include ForkSafely or FSDB itself, or they
299
+ # should make sure to call FSDB.fork instead of Kernel.fork. If you use
300
+ # mutexes (outside of those in FSDB), they should be FSDB::Mutexes.
301
+ module ForkSafely
302
+ include Sync::ForkSafely
303
+ end
304
+ include ForkSafely
305
+
306
+ end # module FSDB
307
+
308
+
309
+ if __FILE__ == $0
310
+ include FSDB::ForkSafely
311
+
312
+ m = FSDB::Synchronizer.new
313
+
314
+ EX = FSDB::Synchronizer::EX
315
+
316
+ Thread.new { m.synchronize(EX) { sleep 1 } }
317
+
318
+ fork do
319
+ m.synchronize(EX) {
320
+ puts "Didn't get here if you used standard sync or fork."
321
+ }
322
+ end
323
+
324
+ m.synchronize(EX) { puts "Got here." }
325
+
326
+ Process.wait
327
+ end
@@ -0,0 +1,86 @@
1
+ <?xml version="1.0" ?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <html xmlns="http://www.w3.org/1999/xhtml">
6
+ <head>
7
+ <title>Untitled</title>
8
+ </head>
9
+ <body>
10
+ <p>require 'thread' # for exclusive
11
+ require 'fsdb/file-lock'
12
+ require 'fsdb/modex.rb'; Sync = FSDB::Modex</p>
13
+ <p>include File::OpenLock</p>
14
+ <p>process_count = 2
15
+ thread_count = 2
16
+ rep_count = (ARGV.shift || 10000).to_i
17
+ modex = Sync.new</p>
18
+ <p>test_file = '/tmp/test-file-lock.dat' ## also try NFS</p>
19
+ <p>File.open(test_file, "w") {|f| Marshal.dump(0, f)}</p>
20
+ <p>(0...process_count).each do</p>
21
+ <pre>fork do
22
+
23
+ increments = 0
24
+
25
+ threads =
26
+ (0...thread_count).map do
27
+ Thread.new do
28
+ (0...rep_count).each do
29
+ if rand(100) &lt; 50
30
+ modex.synchronize(Sync::SH) do
31
+ open_read_lock(test_file) do |f|
32
+ str = f.read
33
+ data = Marshal.load(str)
34
+ end
35
+ end
36
+ else
37
+ modex.synchronize(Sync::EX) do
38
+ open_write_lock(test_file) do |f|
39
+ str = f.read
40
+ data = Marshal.load(str)
41
+ data += 1
42
+ f.rewind; f.truncate(0)
43
+ Marshal.dump(data, f)
44
+ f.flush
45
+ Thread.exclusive {increments += 1}
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ threads.each {|thread| thread.join}
54
+
55
+ File.open("#{test_file}#{Process.pid}", "w") do |f|
56
+ Marshal.dump(increments, f)
57
+ end
58
+
59
+ end</pre>
60
+ <p>end</p>
61
+ <p>Thread.new do</p>
62
+ <pre>count = 0
63
+ loop do
64
+ puts count
65
+ sleep 1
66
+ count += 1
67
+ end </pre>
68
+ <p>end</p>
69
+ <p>increments = 0
70
+ (0...process_count).each do</p>
71
+ <pre>pid = Process.wait
72
+ File.open("#{test_file}#{pid}", "r") do |f|
73
+ increments += Marshal.load(f)
74
+ end</pre>
75
+ <p>end</p>
76
+ <p>data = File.open(test_file, "r") {|f| Marshal.load(f)}</p>
77
+ <p>if data == increments</p>
78
+ <pre>puts "Equal counts: #{data}"</pre>
79
+ <p>else</p>
80
+ <pre>puts "Not equal:"
81
+ puts " increments: #{increments}"
82
+ puts " data : #{data}"</pre>
83
+ <p>end</p>
84
+
85
+ </body>
86
+ </html>
@@ -0,0 +1,84 @@
1
+ require 'thread' # for exclusive
2
+ require 'fsdb/file-lock'
3
+ require 'fsdb/modex.rb'; Sync = FSDB::Modex
4
+ #require 'sync'
5
+
6
+ include File::OpenLock
7
+
8
+ process_count = 2
9
+ thread_count = 2
10
+ rep_count = (ARGV.shift || 10000).to_i
11
+ modex = Sync.new
12
+
13
+ test_file = '/tmp/test-file-lock.dat' ## also try NFS
14
+
15
+ File.open(test_file, "w") {|f| Marshal.dump(0, f)}
16
+
17
+ (0...process_count).each do
18
+ fork do
19
+
20
+ increments = 0
21
+
22
+ threads =
23
+ (0...thread_count).map do
24
+ Thread.new do
25
+ (0...rep_count).each do
26
+ if rand(100) < 50
27
+ modex.synchronize(Sync::SH) do
28
+ open_read_lock(test_file) do |f|
29
+ str = f.read
30
+ data = Marshal.load(str)
31
+ end
32
+ end
33
+ else
34
+ modex.synchronize(Sync::EX) do
35
+ open_write_lock(test_file) do |f|
36
+ str = f.read
37
+ data = Marshal.load(str)
38
+ data += 1
39
+ f.rewind; f.truncate(0)
40
+ Marshal.dump(data, f)
41
+ f.flush
42
+ Thread.exclusive {increments += 1}
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ threads.each {|thread| thread.join}
51
+
52
+ File.open("#{test_file}#{Process.pid}", "w") do |f|
53
+ Marshal.dump(increments, f)
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ Thread.new do
60
+ count = 0
61
+ loop do
62
+ puts count
63
+ sleep 1
64
+ count += 1
65
+ end
66
+ end
67
+
68
+ increments = 0
69
+ (0...process_count).each do
70
+ pid = Process.wait
71
+ File.open("#{test_file}#{pid}", "r") do |f|
72
+ increments += Marshal.load(f)
73
+ end
74
+ end
75
+
76
+ data = File.open(test_file, "r") {|f| Marshal.load(f)}
77
+
78
+ if data == increments
79
+ puts "Equal counts: #{data}"
80
+ else
81
+ puts "Not equal:"
82
+ puts " increments: #{increments}"
83
+ puts " data : #{data}"
84
+ end