fsdb 0.5 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/{RELEASE-NOTES → History.txt} +6 -0
  2. data/{README → README.txt} +26 -17
  3. data/examples/flat.rb +146 -0
  4. data/examples/fsdb-example.rb +28 -0
  5. data/examples/rbformat.rb +17 -0
  6. data/examples/yaml2.rb +29 -0
  7. data/junk/OLDRakefile +98 -0
  8. data/junk/OLDRakefile2 +55 -0
  9. data/junk/check-cache.rb +18 -0
  10. data/junk/create-lock.rb +25 -0
  11. data/junk/doc/old-api/classes/FSDB.html +139 -0
  12. data/junk/doc/old-api/classes/FSDB/Database.html +953 -0
  13. data/junk/doc/old-api/classes/FSDB/Database.src/M000029.html +16 -0
  14. data/junk/doc/old-api/classes/FSDB/Database.src/M000030.html +16 -0
  15. data/junk/doc/old-api/classes/FSDB/Database.src/M000031.html +16 -0
  16. data/junk/doc/old-api/classes/FSDB/Database.src/M000032.html +16 -0
  17. data/junk/doc/old-api/classes/FSDB/Database.src/M000033.html +33 -0
  18. data/junk/doc/old-api/classes/FSDB/Database.src/M000034.html +18 -0
  19. data/junk/doc/old-api/classes/FSDB/Database.src/M000035.html +22 -0
  20. data/junk/doc/old-api/classes/FSDB/Database.src/M000036.html +16 -0
  21. data/junk/doc/old-api/classes/FSDB/Database.src/M000037.html +22 -0
  22. data/junk/doc/old-api/classes/FSDB/Database.src/M000038.html +43 -0
  23. data/junk/doc/old-api/classes/FSDB/Database.src/M000039.html +25 -0
  24. data/junk/doc/old-api/classes/FSDB/Database.src/M000040.html +43 -0
  25. data/junk/doc/old-api/classes/FSDB/Database.src/M000041.html +23 -0
  26. data/junk/doc/old-api/classes/FSDB/Database.src/M000042.html +22 -0
  27. data/junk/doc/old-api/classes/FSDB/Database.src/M000043.html +16 -0
  28. data/junk/doc/old-api/classes/FSDB/Database.src/M000044.html +16 -0
  29. data/junk/doc/old-api/classes/FSDB/Database.src/M000045.html +18 -0
  30. data/junk/doc/old-api/classes/FSDB/Database.src/M000046.html +18 -0
  31. data/junk/doc/old-api/classes/FSDB/Database.src/M000047.html +18 -0
  32. data/junk/doc/old-api/classes/FSDB/Database.src/M000048.html +16 -0
  33. data/junk/doc/old-api/classes/FSDB/Database.src/M000049.html +71 -0
  34. data/junk/doc/old-api/classes/FSDB/Database.src/M000050.html +43 -0
  35. data/junk/doc/old-api/classes/FSDB/Database.src/M000051.html +53 -0
  36. data/junk/doc/old-api/classes/FSDB/Database.src/M000052.html +44 -0
  37. data/junk/doc/old-api/classes/FSDB/Database.src/M000053.html +39 -0
  38. data/junk/doc/old-api/classes/FSDB/Database.src/M000054.html +72 -0
  39. data/junk/doc/old-api/classes/FSDB/Database.src/M000055.html +39 -0
  40. data/junk/doc/old-api/classes/FSDB/Database.src/M000056.html +18 -0
  41. data/junk/doc/old-api/classes/FSDB/Database.src/M000057.html +18 -0
  42. data/junk/doc/old-api/classes/FSDB/Database.src/M000058.html +18 -0
  43. data/junk/doc/old-api/classes/FSDB/Database.src/M000059.html +18 -0
  44. data/junk/doc/old-api/classes/FSDB/Database.src/M000060.html +18 -0
  45. data/junk/doc/old-api/classes/FSDB/Database.src/M000061.html +23 -0
  46. data/junk/doc/old-api/classes/FSDB/Database.src/M000062.html +23 -0
  47. data/junk/doc/old-api/classes/FSDB/Database.src/M000063.html +18 -0
  48. data/junk/doc/old-api/classes/FSDB/Database.src/M000064.html +18 -0
  49. data/junk/doc/old-api/classes/FSDB/Database/AbortedTransaction.html +118 -0
  50. data/junk/doc/old-api/classes/FSDB/Database/CreateFileError.html +120 -0
  51. data/junk/doc/old-api/classes/FSDB/Database/DirIsImmutableError.html +117 -0
  52. data/junk/doc/old-api/classes/FSDB/Database/DirNotEmptyError.html +117 -0
  53. data/junk/doc/old-api/classes/FSDB/Database/FormatError.html +117 -0
  54. data/junk/doc/old-api/classes/FSDB/Database/MissingFileError.html +117 -0
  55. data/junk/doc/old-api/classes/FSDB/Database/MissingObjectError.html +117 -0
  56. data/junk/doc/old-api/classes/FSDB/Database/NotDirError.html +118 -0
  57. data/junk/doc/old-api/classes/FSDB/Database/PathComponentError.html +120 -0
  58. data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.html +148 -0
  59. data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.src/M000005.html +21 -0
  60. data/junk/doc/old-api/classes/FSDB/DatabaseDebuggable.src/M000007.html +21 -0
  61. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.html +210 -0
  62. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000006.html +22 -0
  63. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000007.html +22 -0
  64. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000008.html +22 -0
  65. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000009.html +22 -0
  66. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000010.html +22 -0
  67. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000011.html +22 -0
  68. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000012.html +22 -0
  69. data/junk/doc/old-api/classes/FSDB/DirectoryIterators.src/M000013.html +22 -0
  70. data/junk/doc/old-api/classes/FSDB/ForkSafely.html +126 -0
  71. data/junk/doc/old-api/classes/FSDB/Modex.html +237 -0
  72. data/junk/doc/old-api/classes/FSDB/Modex.src/M000024.html +21 -0
  73. data/junk/doc/old-api/classes/FSDB/Modex.src/M000025.html +30 -0
  74. data/junk/doc/old-api/classes/FSDB/Modex.src/M000026.html +21 -0
  75. data/junk/doc/old-api/classes/FSDB/Modex.src/M000027.html +30 -0
  76. data/junk/doc/old-api/classes/FSDB/Modex.src/M000028.html +44 -0
  77. data/junk/doc/old-api/classes/FSDB/Modex.src/M000029.html +26 -0
  78. data/junk/doc/old-api/classes/FSDB/Modex.src/M000030.html +48 -0
  79. data/junk/doc/old-api/classes/FSDB/Modex/ForkSafely.html +105 -0
  80. data/junk/doc/old-api/classes/FSDB/Mutex.html +244 -0
  81. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000018.html +19 -0
  82. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000019.html +18 -0
  83. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000020.html +19 -0
  84. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000021.html +18 -0
  85. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000022.html +23 -0
  86. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000023.html +30 -0
  87. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000024.html +26 -0
  88. data/junk/doc/old-api/classes/FSDB/Mutex.src/M000025.html +21 -0
  89. data/junk/doc/old-api/classes/FSDB/Mutex/ForkSafely.html +105 -0
  90. data/junk/doc/old-api/classes/FSDB/PathUtilities.html +257 -0
  91. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000012.html +23 -0
  92. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000013.html +18 -0
  93. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000014.html +23 -0
  94. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000015.html +18 -0
  95. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000016.html +18 -0
  96. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000017.html +22 -0
  97. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000018.html +23 -0
  98. data/junk/doc/old-api/classes/FSDB/PathUtilities.src/M000019.html +18 -0
  99. data/junk/doc/old-api/classes/FSDB/PathUtilities/InvalidPathError.html +111 -0
  100. data/junk/doc/old-api/classes/File.html +272 -0
  101. data/junk/doc/old-api/classes/File.src/M000001.html +17 -0
  102. data/junk/doc/old-api/classes/File.src/M000002.html +17 -0
  103. data/junk/doc/old-api/classes/File.src/M000003.html +20 -0
  104. data/junk/doc/old-api/classes/File.src/M000004.html +20 -0
  105. data/junk/doc/old-api/classes/File.src/M000005.html +32 -0
  106. data/junk/doc/old-api/classes/File.src/M000006.html +32 -0
  107. data/junk/doc/old-api/created.rid +1 -0
  108. data/junk/doc/old-api/files/README.html +112 -0
  109. data/junk/doc/old-api/files/RELEASE-NOTES.html +233 -0
  110. data/junk/doc/old-api/files/fsdb_txt.html +888 -0
  111. data/junk/doc/old-api/files/lib/fsdb/database_rb.html +115 -0
  112. data/junk/doc/old-api/files/lib/fsdb/file-lock_rb.html +109 -0
  113. data/junk/doc/old-api/files/lib/fsdb/modex_rb.html +121 -0
  114. data/junk/doc/old-api/files/lib/fsdb/mutex_rb.html +108 -0
  115. data/junk/doc/old-api/files/lib/fsdb/util_rb.html +108 -0
  116. data/junk/doc/old-api/fr_class_index.html +47 -0
  117. data/junk/doc/old-api/fr_file_index.html +34 -0
  118. data/junk/doc/old-api/fr_method_index.html +90 -0
  119. data/junk/doc/old-api/index.html +24 -0
  120. data/junk/doc/old-api/rdoc-style.css +208 -0
  121. data/junk/file-lock-nb.rb +15 -0
  122. data/junk/fl.rb +144 -0
  123. data/junk/flock-test.rb +39 -0
  124. data/junk/fsdb.kateproject +47 -0
  125. data/junk/fsdb.prj +196 -0
  126. data/junk/fsdb.sf +46 -0
  127. data/junk/insert-dir.rb +48 -0
  128. data/junk/lock-test-bug.rb +150 -0
  129. data/junk/lock-test-too-simple.rb +136 -0
  130. data/junk/lock-test.rb +151 -0
  131. data/{script → junk}/mkrdoc +0 -0
  132. data/junk/restore-fsdb.rb +37 -0
  133. data/junk/rf.txt +5 -0
  134. data/junk/solaris-bug-fixed.rb +184 -0
  135. data/junk/solaris-bug.rb +182 -0
  136. data/junk/solaris-bug.txt +43 -0
  137. data/junk/sync.rb +327 -0
  138. data/junk/test-file-lock.html +86 -0
  139. data/junk/test-file-lock.rb +84 -0
  140. data/junk/test-processes.rb +131 -0
  141. data/junk/test-threads.rb +113 -0
  142. data/junk/wiki-mutex.rb +108 -0
  143. data/lib/fsdb/database.rb +5 -3
  144. data/lib/fsdb/delegatable.rb +21 -0
  145. data/lib/fsdb/faster-modex.rb +223 -0
  146. data/lib/fsdb/faster-mutex.rb +138 -0
  147. data/lib/fsdb/mutex.rb +4 -1
  148. data/lib/fsdb/persistent.rb +91 -0
  149. data/lib/fsdb/read-write-object.rb +36 -0
  150. data/lib/fsdb/server.rb +44 -0
  151. data/misc/fsdb-blorubu.txt +47 -0
  152. data/misc/mtime-and-file-id.txt +23 -0
  153. data/misc/posixlock.txt +148 -0
  154. data/rakefile +39 -0
  155. data/tasks/ann.rake +80 -0
  156. data/tasks/bones.rake +20 -0
  157. data/tasks/gem.rake +201 -0
  158. data/tasks/git.rake +40 -0
  159. data/tasks/notes.rake +27 -0
  160. data/tasks/post_load.rake +34 -0
  161. data/tasks/rdoc.rake +51 -0
  162. data/tasks/rubyforge.rake +55 -0
  163. data/tasks/setup.rb +292 -0
  164. data/tasks/spec.rake +54 -0
  165. data/tasks/svn.rake +47 -0
  166. data/tasks/test.rake +40 -0
  167. data/tasks/zentest.rake +36 -0
  168. data/test/err.txt +31 -0
  169. data/test/runs.rb +8 -0
  170. data/test/test-file-lock.rb +78 -0
  171. data/test/test-util.rb +1 -0
  172. data/test/trap.rb +31 -0
  173. metadata +198 -35
  174. data/Manifest +0 -36
  175. data/Rakefile +0 -10
  176. data/fsdb.gemspec +0 -113
@@ -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' ===============================================================================