fsdb 0.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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