fsdb 0.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{RELEASE-NOTES → History.txt} +6 -0
- data/{README → README.txt} +26 -17
- data/examples/flat.rb +146 -0
- data/examples/fsdb-example.rb +28 -0
- data/examples/rbformat.rb +17 -0
- data/examples/yaml2.rb +29 -0
- data/junk/OLDRakefile +98 -0
- data/junk/OLDRakefile2 +55 -0
- data/junk/check-cache.rb +18 -0
- data/junk/create-lock.rb +25 -0
- data/junk/doc/old-api/classes/FSDB.html +139 -0
- data/junk/doc/old-api/classes/FSDB/Database.html +953 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000029.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000030.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000031.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000032.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000033.html +33 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000034.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000035.html +22 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000036.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000037.html +22 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000038.html +43 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000039.html +25 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000040.html +43 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000041.html +23 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000042.html +22 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000043.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000044.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000045.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000046.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000047.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000048.html +16 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000049.html +71 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000050.html +43 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000051.html +53 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000052.html +44 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000053.html +39 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000054.html +72 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000055.html +39 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000056.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000057.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000058.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000059.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000060.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000061.html +23 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000062.html +23 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000063.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database.src/M000064.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Database/AbortedTransaction.html +118 -0
- data/junk/doc/old-api/classes/FSDB/Database/CreateFileError.html +120 -0
- data/junk/doc/old-api/classes/FSDB/Database/DirIsImmutableError.html +117 -0
- data/junk/doc/old-api/classes/FSDB/Database/DirNotEmptyError.html +117 -0
- data/junk/doc/old-api/classes/FSDB/Database/FormatError.html +117 -0
- data/junk/doc/old-api/classes/FSDB/Database/MissingFileError.html +117 -0
- data/junk/doc/old-api/classes/FSDB/Database/MissingObjectError.html +117 -0
- data/junk/doc/old-api/classes/FSDB/Database/NotDirError.html +118 -0
- data/junk/doc/old-api/classes/FSDB/Database/PathComponentError.html +120 -0
- data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.html +148 -0
- data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.src/M000005.html +21 -0
- data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.src/M000007.html +21 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.html +210 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000006.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000007.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000008.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000009.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000010.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000011.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000012.html +22 -0
- data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000013.html +22 -0
- data/junk/doc/old-api/classes/FSDB/ForkSafely.html +126 -0
- data/junk/doc/old-api/classes/FSDB/Modex.html +237 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000024.html +21 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000025.html +30 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000026.html +21 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000027.html +30 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000028.html +44 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000029.html +26 -0
- data/junk/doc/old-api/classes/FSDB/Modex.src/M000030.html +48 -0
- data/junk/doc/old-api/classes/FSDB/Modex/ForkSafely.html +105 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.html +244 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000018.html +19 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000019.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000020.html +19 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000021.html +18 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000022.html +23 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000023.html +30 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000024.html +26 -0
- data/junk/doc/old-api/classes/FSDB/Mutex.src/M000025.html +21 -0
- data/junk/doc/old-api/classes/FSDB/Mutex/ForkSafely.html +105 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.html +257 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000012.html +23 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000013.html +18 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000014.html +23 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000015.html +18 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000016.html +18 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000017.html +22 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000018.html +23 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000019.html +18 -0
- data/junk/doc/old-api/classes/FSDB/PathUtilities/InvalidPathError.html +111 -0
- data/junk/doc/old-api/classes/File.html +272 -0
- data/junk/doc/old-api/classes/File.src/M000001.html +17 -0
- data/junk/doc/old-api/classes/File.src/M000002.html +17 -0
- data/junk/doc/old-api/classes/File.src/M000003.html +20 -0
- data/junk/doc/old-api/classes/File.src/M000004.html +20 -0
- data/junk/doc/old-api/classes/File.src/M000005.html +32 -0
- data/junk/doc/old-api/classes/File.src/M000006.html +32 -0
- data/junk/doc/old-api/created.rid +1 -0
- data/junk/doc/old-api/files/README.html +112 -0
- data/junk/doc/old-api/files/RELEASE-NOTES.html +233 -0
- data/junk/doc/old-api/files/fsdb_txt.html +888 -0
- data/junk/doc/old-api/files/lib/fsdb/database_rb.html +115 -0
- data/junk/doc/old-api/files/lib/fsdb/file-lock_rb.html +109 -0
- data/junk/doc/old-api/files/lib/fsdb/modex_rb.html +121 -0
- data/junk/doc/old-api/files/lib/fsdb/mutex_rb.html +108 -0
- data/junk/doc/old-api/files/lib/fsdb/util_rb.html +108 -0
- data/junk/doc/old-api/fr_class_index.html +47 -0
- data/junk/doc/old-api/fr_file_index.html +34 -0
- data/junk/doc/old-api/fr_method_index.html +90 -0
- data/junk/doc/old-api/index.html +24 -0
- data/junk/doc/old-api/rdoc-style.css +208 -0
- data/junk/file-lock-nb.rb +15 -0
- data/junk/fl.rb +144 -0
- data/junk/flock-test.rb +39 -0
- data/junk/fsdb.kateproject +47 -0
- data/junk/fsdb.prj +196 -0
- data/junk/fsdb.sf +46 -0
- data/junk/insert-dir.rb +48 -0
- data/junk/lock-test-bug.rb +150 -0
- data/junk/lock-test-too-simple.rb +136 -0
- data/junk/lock-test.rb +151 -0
- data/{script → junk}/mkrdoc +0 -0
- data/junk/restore-fsdb.rb +37 -0
- data/junk/rf.txt +5 -0
- data/junk/solaris-bug-fixed.rb +184 -0
- data/junk/solaris-bug.rb +182 -0
- data/junk/solaris-bug.txt +43 -0
- data/junk/sync.rb +327 -0
- data/junk/test-file-lock.html +86 -0
- data/junk/test-file-lock.rb +84 -0
- data/junk/test-processes.rb +131 -0
- data/junk/test-threads.rb +113 -0
- data/junk/wiki-mutex.rb +108 -0
- data/lib/fsdb/database.rb +5 -3
- data/lib/fsdb/delegatable.rb +21 -0
- data/lib/fsdb/faster-modex.rb +223 -0
- data/lib/fsdb/faster-mutex.rb +138 -0
- data/lib/fsdb/mutex.rb +4 -1
- data/lib/fsdb/persistent.rb +91 -0
- data/lib/fsdb/read-write-object.rb +36 -0
- data/lib/fsdb/server.rb +44 -0
- data/misc/fsdb-blorubu.txt +47 -0
- data/misc/mtime-and-file-id.txt +23 -0
- data/misc/posixlock.txt +148 -0
- data/rakefile +39 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/err.txt +31 -0
- data/test/runs.rb +8 -0
- data/test/test-file-lock.rb +78 -0
- data/test/test-util.rb +1 -0
- data/test/trap.rb +31 -0
- metadata +198 -35
- data/Manifest +0 -36
- data/Rakefile +0 -10
- data/fsdb.gemspec +0 -113
data/junk/insert-dir.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
def insert(path, object)
|
2
|
+
abs_path = absolute(path)
|
3
|
+
file_id = make_file_id(abs_path)
|
4
|
+
object_exclusive file_id do |cache_entry|
|
5
|
+
open_write_lock(path) do |f|
|
6
|
+
dump(object, f)
|
7
|
+
cache_entry.update(f.mtime, inc_version_of(f, cache_entry), object)
|
8
|
+
object
|
9
|
+
end
|
10
|
+
end
|
11
|
+
rescue DirIsImmutableError
|
12
|
+
begin
|
13
|
+
ary = object.to_a
|
14
|
+
# when default to_a becomes obsolete, this will be reported as
|
15
|
+
# an error, which is ok--it will be caught and reported below.
|
16
|
+
raise unless ary.all?{|x|x.size == 2}
|
17
|
+
rescue StandardError
|
18
|
+
raise DirIsImmutableError,
|
19
|
+
"Cannot insert given object at dir #{path} in #{inspect}"
|
20
|
+
end
|
21
|
+
ary.each do |k,v|
|
22
|
+
insert(File.join(path, k), v)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def test_insert_dir
|
27
|
+
@db['insert_dir/'] = {
|
28
|
+
'path1' => 1,
|
29
|
+
'path2' => 2
|
30
|
+
}
|
31
|
+
assert_equal(1, @db['insert_dir/path1'])
|
32
|
+
assert_equal(2, @db['insert_dir/path2'])
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
__END__
|
37
|
+
|
38
|
+
- FSDB::Database#insert now allows
|
39
|
+
|
40
|
+
db['dir/'] = {
|
41
|
+
'path1' => obj1,
|
42
|
+
'path2' => obj2
|
43
|
+
}
|
44
|
+
|
45
|
+
as a shorthand for
|
46
|
+
|
47
|
+
db['dir/path1'] = obj1
|
48
|
+
db['dir/path2'] = obj2
|
@@ -0,0 +1,150 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'sync'
|
5
|
+
|
6
|
+
@path = '/tmp/foo'
|
7
|
+
|
8
|
+
@cache_mutex = Mutex.new
|
9
|
+
|
10
|
+
def make_entry
|
11
|
+
@cache_mutex.synchronize do
|
12
|
+
@cache = Mutex.new
|
13
|
+
@sync = Synchronizer.new
|
14
|
+
@object = nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# This is just for housekeeping, so that stale entries don't result
|
19
|
+
# in unused, but uncollectable, CacheEntry objects.
|
20
|
+
def clear_entry
|
21
|
+
@cache_mutex.synchronize do
|
22
|
+
@cache = nil
|
23
|
+
@sync = nil
|
24
|
+
@object = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def object(f)
|
29
|
+
@cache.synchronize do
|
30
|
+
@object ||= f.read
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def sync_object_shared
|
35
|
+
@sync.synchronize(Synchronizer::SH) {yield}
|
36
|
+
end
|
37
|
+
|
38
|
+
def sync_object_exclusive
|
39
|
+
@sync.synchronize(Synchronizer::EX) {yield}
|
40
|
+
end
|
41
|
+
|
42
|
+
def browse
|
43
|
+
make_entry
|
44
|
+
sync_object_shared do
|
45
|
+
open_read_lock(@path) do |f|
|
46
|
+
yield object(f)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def change
|
52
|
+
make_entry
|
53
|
+
sync_object_exclusive do
|
54
|
+
open_write_lock(@path) do |f|
|
55
|
+
object = object(f)
|
56
|
+
yield object
|
57
|
+
f.write(object)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def open_read_lock(path)
|
63
|
+
File.open(path, "r") do |f|
|
64
|
+
begin
|
65
|
+
f.flock(File::LOCK_SH)
|
66
|
+
yield f
|
67
|
+
ensure
|
68
|
+
f.flock(File::LOCK_UN)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def open_write_lock(path)
|
74
|
+
File.open(path, "r+") do |f|
|
75
|
+
f.rewind
|
76
|
+
begin
|
77
|
+
f.flock(File::LOCK_EX) ## need to use fcntl for Linux NFS
|
78
|
+
yield f
|
79
|
+
ensure
|
80
|
+
f.flush ## is this necessary? [ruby-talk:16721]
|
81
|
+
f.flock(File::LOCK_UN)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def do_test
|
87
|
+
$stdout.sync = true
|
88
|
+
Thread.abort_on_exception = true
|
89
|
+
|
90
|
+
srand(3765)
|
91
|
+
|
92
|
+
thread_count = 2
|
93
|
+
rep_count = 100
|
94
|
+
max_sleep = 0.01
|
95
|
+
|
96
|
+
File.open(@path, "w") do |f|
|
97
|
+
f.write("0")
|
98
|
+
end
|
99
|
+
|
100
|
+
threads = (0..thread_count).map do |thread_index|
|
101
|
+
Thread.new(thread_index) do |ti|
|
102
|
+
Thread.current[:number] = ti
|
103
|
+
rep_count.times do |iter|
|
104
|
+
Thread.current[:iter] = iter
|
105
|
+
|
106
|
+
case rand(3)
|
107
|
+
|
108
|
+
when 0
|
109
|
+
browse do |tester|
|
110
|
+
old_tester = tester
|
111
|
+
sleep(rand*max_sleep)
|
112
|
+
unless old_tester == tester
|
113
|
+
fail "browse: #{old_tester} != #{tester}"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
when 1
|
118
|
+
change do |tester|
|
119
|
+
tester.replace (tester.to_i + 1).to_s
|
120
|
+
old_tester = tester
|
121
|
+
sleep(rand*max_sleep)
|
122
|
+
unless old_tester == tester
|
123
|
+
fail "browse: #{old_tester} != #{tester}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
else
|
128
|
+
sleep(rand*max_sleep)
|
129
|
+
if rand(20) == 0
|
130
|
+
clear_entry
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
sleep(rep_count * max_sleep * 2)
|
140
|
+
if threads.any? {|t|t.alive?}
|
141
|
+
$stderr.puts "Deadlock!"
|
142
|
+
exit!
|
143
|
+
end
|
144
|
+
|
145
|
+
threads.each do |thread|
|
146
|
+
thread.join
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
do_test
|
@@ -0,0 +1,136 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'sync'
|
5
|
+
#require 'ftools'
|
6
|
+
|
7
|
+
@path = '/tmp/foo'
|
8
|
+
|
9
|
+
@cache_mutex = Mutex.new
|
10
|
+
@sync = Synchronizer.new
|
11
|
+
@object = nil
|
12
|
+
|
13
|
+
def object(f)
|
14
|
+
@cache_mutex.synchronize do
|
15
|
+
@object ||= f.read
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_cache
|
20
|
+
@object = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def sync_object_shared
|
24
|
+
@sync.synchronize(Synchronizer::SH) {yield}
|
25
|
+
end
|
26
|
+
def sync_object_exclusive
|
27
|
+
@sync.synchronize(Synchronizer::EX) {yield}
|
28
|
+
end
|
29
|
+
|
30
|
+
def browse
|
31
|
+
sync_object_shared do
|
32
|
+
open_read_lock(@path) do |f|
|
33
|
+
yield object(f)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def change
|
39
|
+
sync_object_exclusive do
|
40
|
+
open_write_lock(@path) do |f|
|
41
|
+
object = object(f)
|
42
|
+
yield object
|
43
|
+
f.write(object)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def open_read_lock(path)
|
49
|
+
File.open(path, "r") do |f|
|
50
|
+
begin
|
51
|
+
f.flock(File::LOCK_SH)
|
52
|
+
yield f
|
53
|
+
ensure
|
54
|
+
f.flock(File::LOCK_UN)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def open_write_lock(path)
|
60
|
+
File.open(path, "r+") do |f|
|
61
|
+
f.rewind
|
62
|
+
begin
|
63
|
+
f.flock(File::LOCK_EX) ## need to use fcntl for Linux NFS
|
64
|
+
yield f
|
65
|
+
ensure
|
66
|
+
f.flush ## is this necessary? [ruby-talk:16721]
|
67
|
+
f.flock(File::LOCK_UN)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def do_test
|
73
|
+
$stdout.sync = true
|
74
|
+
Thread.abort_on_exception = true
|
75
|
+
|
76
|
+
srand(3765)
|
77
|
+
|
78
|
+
thread_count = 2
|
79
|
+
rep_count = 100
|
80
|
+
max_sleep = 0.01
|
81
|
+
|
82
|
+
File.open(@path, "w") do |f|
|
83
|
+
f.write "0"
|
84
|
+
end
|
85
|
+
|
86
|
+
threads = (0..thread_count).map do |thread_index|
|
87
|
+
Thread.new(thread_index) do |ti|
|
88
|
+
Thread.current[:number] = ti
|
89
|
+
rep_count.times do |iter|
|
90
|
+
Thread.current[:iter] = iter
|
91
|
+
|
92
|
+
case rand(3)
|
93
|
+
|
94
|
+
when 0
|
95
|
+
browse do |tester|
|
96
|
+
old_tester = tester
|
97
|
+
sleep(rand*max_sleep)
|
98
|
+
unless old_tester == tester
|
99
|
+
fail "browse: #{old_tester} != #{tester}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
when 1
|
104
|
+
change do |tester|
|
105
|
+
tester.replace (tester.to_i + 1).to_s
|
106
|
+
old_tester = tester
|
107
|
+
sleep(rand*max_sleep)
|
108
|
+
unless old_tester == tester
|
109
|
+
fail "browse: #{old_tester} != #{tester}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
else
|
114
|
+
sleep(rand*max_sleep)
|
115
|
+
if rand(20) == 0
|
116
|
+
clear_cache
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
sleep(rep_count * max_sleep * 2)
|
126
|
+
if threads.any? {|t|t.alive?}
|
127
|
+
$stderr.puts "Deadlock!"
|
128
|
+
exit!
|
129
|
+
end
|
130
|
+
|
131
|
+
threads.each do |thread|
|
132
|
+
thread.join
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
do_test
|
data/junk/lock-test.rb
ADDED
@@ -0,0 +1,151 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'sync'
|
5
|
+
|
6
|
+
@path = '/tmp/foo'
|
7
|
+
|
8
|
+
@cache_mutex = Mutex.new
|
9
|
+
|
10
|
+
def make_entry
|
11
|
+
@cache_mutex.synchronize do
|
12
|
+
unless @mutex
|
13
|
+
@mutex ||= Mutex.new
|
14
|
+
@sync ||= Synchronizer.new
|
15
|
+
@object = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# This is just for housekeeping, so that stale entries don't result
|
21
|
+
# in unused, but uncollectable, CacheEntry objects.
|
22
|
+
def clear_entry
|
23
|
+
@cache_mutex.synchronize do
|
24
|
+
@mutex = nil
|
25
|
+
@sync = nil
|
26
|
+
@object = nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def object(f)
|
31
|
+
@mutex.synchronize do
|
32
|
+
@object ||= f.read
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def sync_object_shared
|
37
|
+
@sync.synchronize(Synchronizer::SH) {yield}
|
38
|
+
end
|
39
|
+
|
40
|
+
def sync_object_exclusive
|
41
|
+
@sync.synchronize(Synchronizer::EX) {yield}
|
42
|
+
end
|
43
|
+
|
44
|
+
def browse
|
45
|
+
make_entry
|
46
|
+
sync_object_shared do
|
47
|
+
open_read_lock(@path) do |f|
|
48
|
+
yield object(f)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def change
|
54
|
+
make_entry
|
55
|
+
sync_object_exclusive do
|
56
|
+
open_write_lock(@path) do |f|
|
57
|
+
object = object(f)
|
58
|
+
yield object
|
59
|
+
f.write(object)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def open_read_lock(path)
|
65
|
+
File.open(path, "r") do |f|
|
66
|
+
begin
|
67
|
+
f.flock(File::LOCK_SH)
|
68
|
+
yield f
|
69
|
+
ensure
|
70
|
+
f.flock(File::LOCK_UN)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def open_write_lock(path)
|
76
|
+
File.open(path, "r+") do |f|
|
77
|
+
begin
|
78
|
+
f.flock(File::LOCK_EX) ## need to use fcntl for Linux NFS
|
79
|
+
yield f
|
80
|
+
ensure
|
81
|
+
f.flush ## is this necessary? [ruby-talk:16721]
|
82
|
+
f.flock(File::LOCK_UN)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def do_test
|
88
|
+
$stdout.sync = true
|
89
|
+
Thread.abort_on_exception = true
|
90
|
+
|
91
|
+
srand(3765)
|
92
|
+
|
93
|
+
thread_count = 2
|
94
|
+
rep_count = 100
|
95
|
+
max_sleep = 0.01
|
96
|
+
|
97
|
+
File.open(@path, "w") do |f|
|
98
|
+
f.write("0")
|
99
|
+
end
|
100
|
+
|
101
|
+
threads = (0..thread_count).map do |thread_index|
|
102
|
+
Thread.new(thread_index) do |ti|
|
103
|
+
Thread.current[:number] = ti
|
104
|
+
rep_count.times do |iter|
|
105
|
+
Thread.current[:iter] = iter
|
106
|
+
|
107
|
+
case rand(3)
|
108
|
+
|
109
|
+
when 0
|
110
|
+
browse do |tester|
|
111
|
+
old_tester = tester
|
112
|
+
sleep(rand*max_sleep)
|
113
|
+
unless old_tester == tester
|
114
|
+
fail "browse: #{old_tester} != #{tester}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
when 1
|
119
|
+
change do |tester|
|
120
|
+
tester.replace (tester.to_i + 1).to_s
|
121
|
+
old_tester = tester
|
122
|
+
sleep(rand*max_sleep)
|
123
|
+
unless old_tester == tester
|
124
|
+
fail "browse: #{old_tester} != #{tester}"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
else
|
129
|
+
sleep(rand*max_sleep)
|
130
|
+
if rand(20) == 0
|
131
|
+
clear_entry
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
sleep(rep_count * max_sleep * 2)
|
141
|
+
if threads.any? {|t|t.alive?}
|
142
|
+
$stderr.puts "Deadlock!"
|
143
|
+
exit!
|
144
|
+
end
|
145
|
+
|
146
|
+
threads.each do |thread|
|
147
|
+
thread.join
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
do_test
|