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
@@ -0,0 +1,138 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
### only use this if you can ensure Thread.critical is not already set!
|
4
|
+
### it mught be worth implementing a granular atomic-add-based mutex in
|
5
|
+
### place of Thread.critical
|
6
|
+
|
7
|
+
# Make sure we use the fast definition, not the thread.rb one!
|
8
|
+
class Thread # :nodoc:
|
9
|
+
def self.exclusive
|
10
|
+
old = critical
|
11
|
+
self.critical = true
|
12
|
+
yield
|
13
|
+
ensure
|
14
|
+
self.critical = old
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module FSDB
|
19
|
+
|
20
|
+
# Mutex class based on standard thread.rb Mutex, which has some problems:
|
21
|
+
#
|
22
|
+
# - waiters are not a strict queue (try_lock can jump the queue, after
|
23
|
+
# which the queue gets *rotated*). Race condition.
|
24
|
+
#
|
25
|
+
# - doesn't use Thread.exclusive in enough places
|
26
|
+
#
|
27
|
+
# - no way to make dead threads give up the mutex, which is crucial in a fork
|
28
|
+
#
|
29
|
+
# Note: neither this Mutex nor the one in thread.rb is nestable.
|
30
|
+
#
|
31
|
+
class Mutex
|
32
|
+
def initialize
|
33
|
+
@waiting = []
|
34
|
+
@locked = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def locked?
|
38
|
+
@locked
|
39
|
+
end
|
40
|
+
|
41
|
+
def try_lock
|
42
|
+
Thread.critical = true
|
43
|
+
if not @locked
|
44
|
+
@locked = Thread.current
|
45
|
+
rslt = true
|
46
|
+
end
|
47
|
+
Thread.critical = false
|
48
|
+
rslt
|
49
|
+
end
|
50
|
+
|
51
|
+
def lock
|
52
|
+
thread = Thread.current
|
53
|
+
Thread.critical = true
|
54
|
+
if @locked
|
55
|
+
@waiting.push thread
|
56
|
+
Thread.stop
|
57
|
+
unless @locked == thread
|
58
|
+
raise ThreadError, "queue was jumped"
|
59
|
+
end
|
60
|
+
else
|
61
|
+
@locked = thread
|
62
|
+
end
|
63
|
+
Thread.critical = false
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def unlock
|
68
|
+
return unless @locked
|
69
|
+
|
70
|
+
Thread.critical = true; t = wake_next_waiter; Thread.critical = false
|
71
|
+
|
72
|
+
begin
|
73
|
+
t.run if t
|
74
|
+
rescue ThreadError
|
75
|
+
end
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def synchronize
|
80
|
+
lock
|
81
|
+
yield
|
82
|
+
ensure
|
83
|
+
unlock
|
84
|
+
end
|
85
|
+
|
86
|
+
def remove_dead # :nodoc:
|
87
|
+
Thread.critical = true
|
88
|
+
@waiting = @waiting.select {|t| t.alive?}
|
89
|
+
wake_next_waiter if @locked and not @locked.alive?
|
90
|
+
Thread.critical = false
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
def wake_next_waiter
|
95
|
+
t = @waiting.shift
|
96
|
+
t.wakeup if t
|
97
|
+
@locked = t
|
98
|
+
rescue ThreadError
|
99
|
+
retry
|
100
|
+
end
|
101
|
+
|
102
|
+
module ForkSafely
|
103
|
+
def fork # :nodoc:
|
104
|
+
super do
|
105
|
+
ObjectSpace.each_object(Mutex) { |m| m.remove_dead }
|
106
|
+
yield
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# FSDB users who fork should include ForkSafely or FSDB itself. If you use
|
113
|
+
# mutexes (outside of those in FSDB), they should be FSDB::Mutexes.
|
114
|
+
module ForkSafely
|
115
|
+
include Mutex::ForkSafely
|
116
|
+
end
|
117
|
+
include ForkSafely
|
118
|
+
|
119
|
+
end # module FSDB
|
120
|
+
|
121
|
+
|
122
|
+
if __FILE__ == $0
|
123
|
+
# Stress test is in fsdb/test/test-mutex.rb. This is just to show fork usage.
|
124
|
+
|
125
|
+
include FSDB::ForkSafely
|
126
|
+
|
127
|
+
m = FSDB::Mutex.new
|
128
|
+
|
129
|
+
Thread.new { m.synchronize { sleep 1 } }
|
130
|
+
|
131
|
+
fork do
|
132
|
+
m.synchronize { puts "Didn't get here if you used standard mutex or fork." }
|
133
|
+
end
|
134
|
+
|
135
|
+
m.synchronize { puts "Got here." }
|
136
|
+
|
137
|
+
Process.wait
|
138
|
+
end
|
data/lib/fsdb/mutex.rb
CHANGED
@@ -29,6 +29,8 @@ class Mutex
|
|
29
29
|
def initialize
|
30
30
|
@waiting = []
|
31
31
|
@locked = nil
|
32
|
+
@waiting.taint # enable tainted comunication
|
33
|
+
self.taint
|
32
34
|
end
|
33
35
|
|
34
36
|
def locked?
|
@@ -37,7 +39,7 @@ class Mutex
|
|
37
39
|
|
38
40
|
def try_lock
|
39
41
|
Thread.exclusive do
|
40
|
-
if not @locked
|
42
|
+
if not @locked # and @waiting.empty? # not needed
|
41
43
|
@locked = Thread.current
|
42
44
|
true
|
43
45
|
end
|
@@ -83,6 +85,7 @@ class Mutex
|
|
83
85
|
Thread.exclusive do
|
84
86
|
@waiting = @waiting.select {|t| t.alive?}
|
85
87
|
wake_next_waiter if @locked and not @locked.alive?
|
88
|
+
## what if @locked thread left the resource in an inconsistent state?
|
86
89
|
end
|
87
90
|
end
|
88
91
|
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'thread'
|
4
|
+
require 'ftools'
|
5
|
+
require 'fsdb/file-lock'
|
6
|
+
|
7
|
+
# Mixin for an object that persists in a file by itself.
|
8
|
+
#
|
9
|
+
# References from the object to objects which need to persist separately
|
10
|
+
# should be through nonpersistent_attr_accessors. Otherwise, objects
|
11
|
+
# referred to in attrs will persist in the same file.
|
12
|
+
|
13
|
+
module Persistent
|
14
|
+
|
15
|
+
def persistent_mutex
|
16
|
+
@persistent_mutex ||
|
17
|
+
Thread.exclusive do
|
18
|
+
@persistent_mutex ||= Mutex.new # ||= to prevent race condition
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Save the persistent object (and all of its persistent references) to
|
23
|
+
# its file. If a block is given, call it (with self) in the context of
|
24
|
+
# locks that protect the file from other threads and processes. This can
|
25
|
+
# be used to atomically save related objects in separate files.
|
26
|
+
def save
|
27
|
+
persistent_mutex.synchronize do
|
28
|
+
File.makedirs(File.dirname(persistent_file))
|
29
|
+
File.open(persistent_file, "wb") do |f|
|
30
|
+
f.lock_exclusive do
|
31
|
+
dump(f)
|
32
|
+
yield self if block_given?
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def dump(*args)
|
39
|
+
Marshal.dump(self, *args)
|
40
|
+
end
|
41
|
+
|
42
|
+
def persistent_file
|
43
|
+
raise "#{self.class} must define the #persistent_file method to" +
|
44
|
+
" return the path of the file in which object persists."
|
45
|
+
end
|
46
|
+
|
47
|
+
class << self
|
48
|
+
|
49
|
+
# Need to take care that only one thread in the process is restoring
|
50
|
+
# a particular object, or there will be multiple copies.
|
51
|
+
def restore file
|
52
|
+
object = File.open(file, "rb") do |f|
|
53
|
+
f.lock_shared do
|
54
|
+
load(f)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
object.restore file
|
58
|
+
object
|
59
|
+
end
|
60
|
+
|
61
|
+
def load(*args)
|
62
|
+
Marshal.load(*args)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
# Called when the object is loaded, allowing the object to restore some
|
68
|
+
# state from the path at which it was saved.
|
69
|
+
def restore file; end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
if __FILE__ == $0
|
74
|
+
|
75
|
+
class Foo
|
76
|
+
include Persistent
|
77
|
+
attr_accessor :x
|
78
|
+
attr_accessor :dir
|
79
|
+
def persistent_file; "/tmp/foo"; end
|
80
|
+
def restore file; @dir = File.dirname(file); end
|
81
|
+
end
|
82
|
+
|
83
|
+
foo = Foo.new
|
84
|
+
foo.x = 1
|
85
|
+
foo.save
|
86
|
+
foo.x = 2
|
87
|
+
foo = Persistent.restore("/tmp/foo")
|
88
|
+
p foo.x
|
89
|
+
p foo.dir
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# based on drb.rb
|
4
|
+
|
5
|
+
class IO
|
6
|
+
def write_object(obj)
|
7
|
+
str = Marshal.dump(obj)
|
8
|
+
packet = [str.size].pack('N') + str
|
9
|
+
write(packet)
|
10
|
+
end
|
11
|
+
|
12
|
+
# returns nil at eof
|
13
|
+
def read_object
|
14
|
+
sz = read(4) # sizeof (N)
|
15
|
+
return nil if sz.nil?
|
16
|
+
raise TypeError, "incomplete header, size == #{sz.size}" if sz.size < 4
|
17
|
+
sz = sz.unpack('N')[0]
|
18
|
+
str = read(sz)
|
19
|
+
raise TypeError, 'incomplete object' if str.nil? || str.size < sz
|
20
|
+
Marshal::load(str)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if __FILE__ == $0
|
25
|
+
|
26
|
+
f = File.open('/tmp/foo', 'w')
|
27
|
+
|
28
|
+
f.write_object([1,2,3])
|
29
|
+
|
30
|
+
f.close
|
31
|
+
|
32
|
+
f = File.open('/tmp/foo', 'r')
|
33
|
+
|
34
|
+
p f.read_object
|
35
|
+
|
36
|
+
end
|
data/lib/fsdb/server.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'drb'
|
2
|
+
require 'fsdb'
|
3
|
+
|
4
|
+
## can we use ssl?
|
5
|
+
|
6
|
+
module FSDB
|
7
|
+
class Server
|
8
|
+
|
9
|
+
private
|
10
|
+
attr_reader :name, :dir, :transactions
|
11
|
+
|
12
|
+
def initialize name = nil, dir = nil, db_class = nil, opts = {}
|
13
|
+
@name = name || "fsdb-server"
|
14
|
+
@dir = dir || name
|
15
|
+
@db = (db_class || Database).new(@dir, opts)
|
16
|
+
|
17
|
+
@listening = true
|
18
|
+
@transactions = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
# counts transactions running in the server process
|
22
|
+
def transaction
|
23
|
+
Thread.exclusive {@transactions += 1}
|
24
|
+
yield
|
25
|
+
ensure
|
26
|
+
Thread.exclusive {@transactions -= 1}
|
27
|
+
end
|
28
|
+
|
29
|
+
def enter_admin_runlevel
|
30
|
+
@listening = false
|
31
|
+
end
|
32
|
+
|
33
|
+
def leave_admin_runlevel
|
34
|
+
@listening = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_listening
|
38
|
+
unless @listening or user.name == 'admin'
|
39
|
+
raise "Server not listening."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
Like pstore, fsdb is:
|
2
|
+
|
3
|
+
- pure ruby, cross-platform
|
4
|
+
|
5
|
+
- ruby license
|
6
|
+
|
7
|
+
- simple API
|
8
|
+
|
9
|
+
- simple implementation (though less so)
|
10
|
+
|
11
|
+
- transaction based, with abort capability
|
12
|
+
|
13
|
+
However, pstore has some drawbacks:
|
14
|
+
|
15
|
+
- not thread-safe (though it is process-safe)
|
16
|
+
|
17
|
+
- coarse granularity (transaction applies to whole pstore), does not scale well
|
18
|
+
|
19
|
+
- uses marshalling, even if your data is is some other format that doesn't require the overhead of marshalling (e.g., strings, binary data)
|
20
|
+
|
21
|
+
Other advantages of fsdb:
|
22
|
+
|
23
|
+
- can use YAML (or other formats) where you want to (e.g., in user settings, but perhaps not for large ruby objects or binary data). It's easy to specify a mapping from path patterns to data formats.
|
24
|
+
|
25
|
+
- thread-safe, so you can easily wire it up to a multithreaded server, like drb (see examples/server.rb)
|
26
|
+
|
27
|
+
- objects in the database are just files, and so can be manipulated with standard command line tools (including rsync, versioning tools, etc.).
|
28
|
+
|
29
|
+
- granularity is up to you: you can have lots of little objects, if you want, (there are tradeoffs, of course)
|
30
|
+
|
31
|
+
- scales as well as the fs does
|
32
|
+
|
33
|
+
- thoroughly stress-tested, partially unit-tested. (But still not quite stable on Windows.)
|
34
|
+
|
35
|
+
- Can select fcntl-based locking (if platform supports it), which should allow safe use with NFS mounts on linux
|
36
|
+
|
37
|
+
Disadvantages of fsdb:
|
38
|
+
|
39
|
+
- If you want indexes, you need to implement them on top of fsdb. You could do:
|
40
|
+
|
41
|
+
db['name-index'] = RBTree.new
|
42
|
+
|
43
|
+
and define your own methods for adding/removing objects that also updates the name-index. The name-index maps names (or other keys) to paths in the db.
|
44
|
+
|
45
|
+
- Likewise, no SQL, out of the box.
|
46
|
+
|
47
|
+
- Efficiency and reliability depends on the fs. (My benchmarks get on the order of 1000 transactions per sec on a 3 yr old linux box.)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
mtime granularity on win?
|
2
|
+
|
3
|
+
see:
|
4
|
+
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/by_handle_file_information_str.asp
|
5
|
+
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/file_times.asp
|
6
|
+
|
7
|
+
http://www.google.com/search?hl=en&ie=ISO-8859-1&q=unique+file+id+on+windows&btnG=Google+Search
|
8
|
+
|
9
|
+
http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&ixPost=42340
|
10
|
+
|
11
|
+
Windows can give a unique file indentifier using the function GetFileInformationByHandle() (See http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/getfileinformationbyhandle.asp)
|
12
|
+
|
13
|
+
Example: (hFile is a handle to a file)
|
14
|
+
|
15
|
+
BY_HANDLE_FILE_INFORMATION FileInfo;
|
16
|
+
|
17
|
+
GetFileInformationByHandle(hFile, &FileInfo);
|
18
|
+
inode= FileInfo.nFileIndexLow | (FileInfo.nFileIndexHigh << 32);
|
19
|
+
volume=FileInfo.dwVolumeSerialNumber;
|
20
|
+
|
21
|
+
According to Micorsoft : "The identifier (low and high parts) and the volume serial number uniquely identify a file on a single computer. To determine whether two open handles represent the same file, combine this identifier and the volume serial number for each file and compare them."
|
22
|
+
|
23
|
+
|
data/misc/posixlock.txt
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
Subject:
|
2
|
+
[ANN] posixlock
|
3
|
+
From:
|
4
|
+
"Ara.T.Howard" <ahoward@ngdc.noaa.gov>
|
5
|
+
Date:
|
6
|
+
Sat, 6 Dec 2003 05:22:07 +0900
|
7
|
+
To:
|
8
|
+
ruby-talk@ruby-lang.org (ruby-talk ML)
|
9
|
+
Newsgroups:
|
10
|
+
comp.lang.ruby
|
11
|
+
|
12
|
+
|
13
|
+
SYNOPSIS:
|
14
|
+
posixlock
|
15
|
+
use fcntl (vs. flock) based locking for File#flock
|
16
|
+
|
17
|
+
USAGE
|
18
|
+
require 'posixlock' # replaces File#flock!
|
19
|
+
|
20
|
+
|
21
|
+
i currently do not have a place to post software - so here's a little
|
22
|
+
extension that replaces flock with an fcntl based impl for posix compliant
|
23
|
+
locking (safe on nfs) - posted to c.l.r for posterity:
|
24
|
+
|
25
|
+
extconf.rb
|
26
|
+
================
|
27
|
+
require 'mkmf'
|
28
|
+
create_makefile 'posixlock'
|
29
|
+
================
|
30
|
+
|
31
|
+
posixlock.c
|
32
|
+
================
|
33
|
+
#ifdef _WIN32
|
34
|
+
#include "missing/file.h"
|
35
|
+
#endif
|
36
|
+
|
37
|
+
#include "ruby.h"
|
38
|
+
#include "rubyio.h"
|
39
|
+
#include "rubysig.h"
|
40
|
+
|
41
|
+
#ifdef HAVE_UNISTD_H
|
42
|
+
#include <unistd.h>
|
43
|
+
#endif
|
44
|
+
|
45
|
+
#ifdef HAVE_FCNTL_H
|
46
|
+
#include <fcntl.h>
|
47
|
+
#endif
|
48
|
+
|
49
|
+
#include <errno.h>
|
50
|
+
|
51
|
+
extern VALUE rb_cFile;
|
52
|
+
|
53
|
+
# ifndef LOCK_SH
|
54
|
+
# define LOCK_SH 1
|
55
|
+
# endif
|
56
|
+
# ifndef LOCK_EX
|
57
|
+
# define LOCK_EX 2
|
58
|
+
# endif
|
59
|
+
# ifndef LOCK_NB
|
60
|
+
# define LOCK_NB 4
|
61
|
+
# endif
|
62
|
+
# ifndef LOCK_UN
|
63
|
+
# define LOCK_UN 8
|
64
|
+
# endif
|
65
|
+
|
66
|
+
static int
|
67
|
+
posixlock (fd, operation)
|
68
|
+
int fd;
|
69
|
+
int operation;
|
70
|
+
{
|
71
|
+
struct flock lock;
|
72
|
+
|
73
|
+
switch (operation & ~LOCK_NB)
|
74
|
+
{
|
75
|
+
case LOCK_SH:
|
76
|
+
lock.l_type = F_RDLCK;
|
77
|
+
break;
|
78
|
+
case LOCK_EX:
|
79
|
+
lock.l_type = F_WRLCK;
|
80
|
+
break;
|
81
|
+
case LOCK_UN:
|
82
|
+
lock.l_type = F_UNLCK;
|
83
|
+
break;
|
84
|
+
default:
|
85
|
+
errno = EINVAL;
|
86
|
+
return -1;
|
87
|
+
}
|
88
|
+
lock.l_whence = SEEK_SET;
|
89
|
+
lock.l_start = lock.l_len = 0L;
|
90
|
+
return fcntl (fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lock);
|
91
|
+
}
|
92
|
+
|
93
|
+
|
94
|
+
static VALUE
|
95
|
+
rb_file_posixlock (obj, operation)
|
96
|
+
VALUE obj;
|
97
|
+
VALUE operation;
|
98
|
+
{
|
99
|
+
#ifndef __CHECKER__
|
100
|
+
OpenFile *fptr;
|
101
|
+
int ret;
|
102
|
+
|
103
|
+
rb_secure (2);
|
104
|
+
GetOpenFile (obj, fptr);
|
105
|
+
|
106
|
+
if (fptr->mode & FMODE_WRITABLE)
|
107
|
+
{
|
108
|
+
fflush (GetWriteFile (fptr));
|
109
|
+
}
|
110
|
+
retry:
|
111
|
+
TRAP_BEG;
|
112
|
+
ret = posixlock (fileno (fptr->f), NUM2INT (operation));
|
113
|
+
TRAP_END;
|
114
|
+
if (ret < 0)
|
115
|
+
{
|
116
|
+
switch (errno)
|
117
|
+
{
|
118
|
+
case EAGAIN:
|
119
|
+
case EACCES:
|
120
|
+
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
|
121
|
+
case EWOULDBLOCK:
|
122
|
+
#endif
|
123
|
+
return Qfalse;
|
124
|
+
case EINTR:
|
125
|
+
#if defined(ERESTART)
|
126
|
+
case ERESTART:
|
127
|
+
#endif
|
128
|
+
goto retry;
|
129
|
+
}
|
130
|
+
rb_sys_fail (fptr->path);
|
131
|
+
}
|
132
|
+
#endif
|
133
|
+
|
134
|
+
return INT2FIX (0);
|
135
|
+
}
|
136
|
+
|
137
|
+
|
138
|
+
void
|
139
|
+
Init_posixlock()
|
140
|
+
{
|
141
|
+
rb_define_method(rb_cFile, "flock", rb_file_posixlock, 1);
|
142
|
+
}
|
143
|
+
================
|
144
|
+
|
145
|
+
|
146
|
+
|
147
|
+
-a
|
148
|
+
-- ATTN: please update your address books with address below! =============================================================================== | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov | PHONE :: 303.497.6469 | ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328 | STP :: http://www.ngdc.noaa.gov/stp/ | NGDC :: http://www.ngdc.noaa.gov/ | NESDIS :: http://www.nesdis.noaa.gov/ | NOAA :: http://www.noaa.gov/ | US DOC :: http://www.commerce.gov/ | | The difference between art and science is that science is what we | understand well enough to explain to a computer. | Art is everything else. | -- Donald Knuth, "Discover" | | /bin/sh -c 'for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done' ===============================================================================
|