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
@@ -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
@@ -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
+
@@ -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' ===============================================================================