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,888 @@
|
|
1
|
+
<?xml version="1.0" encoding="iso-8859-1"?>
|
2
|
+
<!DOCTYPE html
|
3
|
+
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
4
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
5
|
+
|
6
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
7
|
+
<head>
|
8
|
+
<title>File: fsdb.txt</title>
|
9
|
+
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
10
|
+
<meta http-equiv="Content-Script-Type" content="text/javascript" />
|
11
|
+
<link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
|
12
|
+
<script type="text/javascript">
|
13
|
+
// <![CDATA[
|
14
|
+
|
15
|
+
function popupCode( url ) {
|
16
|
+
window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
|
17
|
+
}
|
18
|
+
|
19
|
+
function toggleCode( id ) {
|
20
|
+
if ( document.getElementById )
|
21
|
+
elem = document.getElementById( id );
|
22
|
+
else if ( document.all )
|
23
|
+
elem = eval( "document.all." + id );
|
24
|
+
else
|
25
|
+
return false;
|
26
|
+
|
27
|
+
elemStyle = elem.style;
|
28
|
+
|
29
|
+
if ( elemStyle.display != "block" ) {
|
30
|
+
elemStyle.display = "block"
|
31
|
+
} else {
|
32
|
+
elemStyle.display = "none"
|
33
|
+
}
|
34
|
+
|
35
|
+
return true;
|
36
|
+
}
|
37
|
+
|
38
|
+
// Make codeblocks hidden by default
|
39
|
+
document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
|
40
|
+
|
41
|
+
// ]]>
|
42
|
+
</script>
|
43
|
+
|
44
|
+
</head>
|
45
|
+
<body>
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
<div id="fileHeader">
|
50
|
+
<h1>fsdb.txt</h1>
|
51
|
+
<table class="header-table">
|
52
|
+
<tr class="top-aligned-row">
|
53
|
+
<td><strong>Path:</strong></td>
|
54
|
+
<td>fsdb.txt
|
55
|
+
</td>
|
56
|
+
</tr>
|
57
|
+
<tr class="top-aligned-row">
|
58
|
+
<td><strong>Last Update:</strong></td>
|
59
|
+
<td>Tue Mar 14 11:20:07 PST 2006</td>
|
60
|
+
</tr>
|
61
|
+
</table>
|
62
|
+
</div>
|
63
|
+
<!-- banner header -->
|
64
|
+
|
65
|
+
<div id="bodyContent">
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
<div id="contextContent">
|
70
|
+
|
71
|
+
<div id="description">
|
72
|
+
<h1>What is <a href="../classes/FSDB.html">FSDB</a>?</h1>
|
73
|
+
<p>
|
74
|
+
<a href="../classes/FSDB.html">FSDB</a> is a file system data base. <a
|
75
|
+
href="../classes/FSDB.html">FSDB</a> provides a thread-safe, process-safe
|
76
|
+
Database class which uses the native file system as its back end and allows
|
77
|
+
multiple file formats and serialization methods. Users access objects in
|
78
|
+
terms of their paths relative to the base directory of the database.
|
79
|
+
It’s very light weight (the state of a Database is essentially just a
|
80
|
+
path string, and code size is very small, under 1K lines, all ruby).
|
81
|
+
</p>
|
82
|
+
<p>
|
83
|
+
<a href="../classes/FSDB.html">FSDB</a> stores bundles of ruby objects at
|
84
|
+
nodes in the file system. Each bundle is saved and restored as a whole, so
|
85
|
+
internal references persist as usual. These bundles are the atoms of
|
86
|
+
transactions. References between bundles are handled through path strings.
|
87
|
+
The format of each bundle on disk can vary; format classes for plain text
|
88
|
+
strings, marshalled data, and yaml data are included, but <a
|
89
|
+
href="../classes/FSDB.html">FSDB</a> can easily be extended to recognize
|
90
|
+
other formats, both binary and text. <a
|
91
|
+
href="../classes/FSDB.html">FSDB</a> treats directories as collections and
|
92
|
+
provides directory iterator methods.
|
93
|
+
</p>
|
94
|
+
<p>
|
95
|
+
<a href="../classes/FSDB.html">FSDB</a> has been tested on a variety of
|
96
|
+
platforms and ruby versions, and is not known to have any problems. (On
|
97
|
+
WindowsME/98/95, multiple processes can access a database unsafely, because
|
98
|
+
flock() is not available on the platform.) See the Testing section for
|
99
|
+
details.
|
100
|
+
</p>
|
101
|
+
<p>
|
102
|
+
<a href="../classes/FSDB.html">FSDB</a> does not yet have any indexing or
|
103
|
+
querying mechanisms, and is probably missing many other useful database
|
104
|
+
features, so it is not a general replacement for RDBs or OODBs. However, if
|
105
|
+
you are looking for a lightweight, concurrent object store with reasonable
|
106
|
+
performance and better granularity than PStore, in pure Ruby, with a Ruby
|
107
|
+
license, take a look at <a href="../classes/FSDB.html">FSDB</a>. Also, if
|
108
|
+
you are looking for an easy way of making an existing file tree look like a
|
109
|
+
database, especially if it has heterogeneous file formats, <a
|
110
|
+
href="../classes/FSDB.html">FSDB</a> might be useful.
|
111
|
+
</p>
|
112
|
+
<h2>Installation</h2>
|
113
|
+
<pre>
|
114
|
+
ruby install.rb config
|
115
|
+
ruby install.rb setup
|
116
|
+
ruby install.rb install
|
117
|
+
</pre>
|
118
|
+
<h2>Synopsis</h2>
|
119
|
+
<pre>
|
120
|
+
require 'fsdb'
|
121
|
+
|
122
|
+
db = FSDB::Database.new('/tmp/my-data')
|
123
|
+
|
124
|
+
db['recent-movies/myself'] = ["LOTR II", "Austin Powers"]
|
125
|
+
puts db['recent-movies/myself'][0] # ==> "LOTR II"
|
126
|
+
|
127
|
+
db.edit 'recent-movies/myself' do |list|
|
128
|
+
list << "A la recherche du temps perdu"
|
129
|
+
end
|
130
|
+
</pre>
|
131
|
+
<h2>Path names</h2>
|
132
|
+
<p>
|
133
|
+
Keys in the database are path strings, which are simply strings in the
|
134
|
+
usual forward-slash delimited format, relative to the database’s
|
135
|
+
directory. There are some points to be aware of when using them to refer to
|
136
|
+
database objects.
|
137
|
+
</p>
|
138
|
+
<ul>
|
139
|
+
<li>Paths to directories are formed in one of two ways:
|
140
|
+
|
141
|
+
<ul>
|
142
|
+
<li>explicitly, with a trailing slash, as in <tt>db[‘foo/’]</tt>
|
143
|
+
|
144
|
+
</li>
|
145
|
+
<li>implicitly, as in <tt>db[‘foo’]</tt> if foo is already a
|
146
|
+
directory, or as in <tt>db[‘foo/bar’]</tt>, which creates
|
147
|
+
<tt>‘foo’</tt> if it did not already exist.
|
148
|
+
|
149
|
+
</li>
|
150
|
+
</ul>
|
151
|
+
<p>
|
152
|
+
The root dir of the database is simply <tt>/</tt>, its child directories
|
153
|
+
are of the form <tt>foo/</tt> and so on. The leading and trailing slashes
|
154
|
+
are both optional.
|
155
|
+
</p>
|
156
|
+
</li>
|
157
|
+
<li>Objects can be stored in various formats, indicated by path name. A typical
|
158
|
+
mapping might be:
|
159
|
+
|
160
|
+
<table>
|
161
|
+
<tr><td valign="top"><tt>foo.obj</tt>:</td><td>Marshalled data (the default for unrecognized extension)
|
162
|
+
|
163
|
+
</td></tr>
|
164
|
+
<tr><td valign="top"><tt>foo.txt</tt>:</td><td>String
|
165
|
+
|
166
|
+
</td></tr>
|
167
|
+
<tr><td valign="top"><tt>foo/</tt>:</td><td>Directory (the contents is presented to the caller as a list of file and
|
168
|
+
subdirectory paths that can be used in browse, edit, etc.)
|
169
|
+
|
170
|
+
</td></tr>
|
171
|
+
<tr><td valign="top"><tt>foo.yml</tt>:</td><td>YAML data—see examples/yaml.rb
|
172
|
+
|
173
|
+
</td></tr>
|
174
|
+
</table>
|
175
|
+
<p>
|
176
|
+
New formats, which correlate filename pattern with serialization behavior,
|
177
|
+
can be defined and plugged in to databases. Each format has its own rules
|
178
|
+
for matching patterns in the file name and recognizing the file. Patterns
|
179
|
+
can be anything with a #=== method (such as a regex). See
|
180
|
+
lib/fsdb/formats.rb examples of defining formats. For examples of
|
181
|
+
associating formats with patterns, see examples/formats.rb.
|
182
|
+
</p>
|
183
|
+
</li>
|
184
|
+
<li>Different notations for the same path, such as
|
185
|
+
|
186
|
+
<pre>
|
187
|
+
/foo/bar
|
188
|
+
foo/bar
|
189
|
+
foo//bar
|
190
|
+
foo/../foo/bar
|
191
|
+
</pre>
|
192
|
+
<p>
|
193
|
+
work correctly, as do paths that denote hard or soft links, if supported on
|
194
|
+
the platform.
|
195
|
+
</p>
|
196
|
+
<p>
|
197
|
+
Links are subject to the same naming convention as normal files with regard
|
198
|
+
to format identification: format is determined by the path within the
|
199
|
+
database used to access the object. Using a different name for a link can
|
200
|
+
be useful if you need to access the file using two different formats (e.g.,
|
201
|
+
plain text via ‘foo.txt’ and tabular data via
|
202
|
+
‘foo.table’ or whatever).
|
203
|
+
</p>
|
204
|
+
</li>
|
205
|
+
<li>Accessing objects in a database is unaffected by the current dir of your
|
206
|
+
process. The database knows it’s own absolute path, and path
|
207
|
+
arguments to the Database API are interpreted relative to that. If you want
|
208
|
+
to work with a subdirectory of the database, and paths relative to that,
|
209
|
+
use Database#subdb:
|
210
|
+
|
211
|
+
<pre>
|
212
|
+
db = Database.new['/tmp']
|
213
|
+
db['foo/bar'] = 1
|
214
|
+
foo = db.subdb('foo')
|
215
|
+
foo['bar'] # ==> 1
|
216
|
+
</pre>
|
217
|
+
</li>
|
218
|
+
<li>Paths that are outside the database (’../../zap’) are allowed,
|
219
|
+
but may or may not be desirable. Use valid? and validate in util.rb to
|
220
|
+
check for them.
|
221
|
+
|
222
|
+
</li>
|
223
|
+
<li>Directories are created when needed. So db[‘a/b/c’] = 1 creates
|
224
|
+
two dirs and one file.
|
225
|
+
|
226
|
+
</li>
|
227
|
+
<li>Files beginning with ’..’ are ignored by fsdb dir iterators,
|
228
|
+
though they can still be accessed in transaction operators. Some such files
|
229
|
+
(<tt>..fsdb.meta.<filename></tt>) are used internally. All others
|
230
|
+
<em>not</em> beginning with <tt>..fsdb</tt> are reserved for applications
|
231
|
+
to use.
|
232
|
+
|
233
|
+
<p>
|
234
|
+
The <tt>..fsdb.meta.<filename></tt> file holds a version number for
|
235
|
+
<filename>, which is used along with mtime to check for changes
|
236
|
+
(mtime usually has a precision of only 1 second). In the future, the file
|
237
|
+
may also be used to hold other metadata. (The meta file is only created
|
238
|
+
when a file is written to and does not need to be created in advance when
|
239
|
+
using existing files as a <a href="../classes/FSDB.html">FSDB</a>.)
|
240
|
+
</p>
|
241
|
+
</li>
|
242
|
+
<li>util.rb has directory iterators, path globbing, and other useful tools.
|
243
|
+
|
244
|
+
</li>
|
245
|
+
</ul>
|
246
|
+
<h2>Transactions</h2>
|
247
|
+
<p>
|
248
|
+
<a href="../classes/FSDB.html">FSDB</a> transactions are thread-safe and
|
249
|
+
process-safe. They can be nested for larger-grained transactions; it is the
|
250
|
+
user’s responsibility to avoid deadlock.
|
251
|
+
</p>
|
252
|
+
<p>
|
253
|
+
<a href="../classes/FSDB.html">FSDB</a> is ACID
|
254
|
+
(atomic/consistent/isolated/durable) to the extent that the underlying file
|
255
|
+
system is. For instance, when an object that has been modified in a
|
256
|
+
transaction is written to the file system, nothing persistent is changed
|
257
|
+
until the final system call to write the data to the OS’s buffers. If
|
258
|
+
there is an interruption (e.g., a power failure) while the OS flushes those
|
259
|
+
buffers to disk, data will not be consistent. If this bothers you, you may
|
260
|
+
want to use a journaling file system. <a
|
261
|
+
href="../classes/FSDB.html">FSDB</a> does not need to do its own journaling
|
262
|
+
because of the availability of good journaling file systems.
|
263
|
+
</p>
|
264
|
+
<p>
|
265
|
+
There are two kinds of transactions:
|
266
|
+
</p>
|
267
|
+
<ul>
|
268
|
+
<li>A simple transfer of a value, as in <tt>db[‘x’]</tt> and
|
269
|
+
<tt>db[‘x’] = 1</tt>.
|
270
|
+
|
271
|
+
<p>
|
272
|
+
Note that a sequence of such transactions is not itself a transaction, and
|
273
|
+
can be affected by other processes and threads.
|
274
|
+
</p>
|
275
|
+
<pre>
|
276
|
+
db['foo/bar'] = [1,2,3]
|
277
|
+
db['foo/bar'] += [4] # This is actually 2 transactions
|
278
|
+
db['foo/bar'][-1]
|
279
|
+
</pre>
|
280
|
+
<p>
|
281
|
+
It is possible for the result of these transactions to be <tt>4</tt>. But,
|
282
|
+
if other threads or processes are scheduled during this code fragment, the
|
283
|
+
result could be a completely different value, or the code could raise an
|
284
|
+
method-missing exception because the object at the path has been replaced
|
285
|
+
with one that does not have the <tt>+</tt> method or the <tt>[ ]</tt>
|
286
|
+
method. The four operations are atomic by themselves, but the sequence is
|
287
|
+
not.
|
288
|
+
</p>
|
289
|
+
<p>
|
290
|
+
Note that changes to a database object using this kind of transaction
|
291
|
+
cannot be made using destructive methods (such as <tt><<</tt>) but
|
292
|
+
only by assignments of the form <tt>db[<path>] = <data></tt>.
|
293
|
+
Note that <tt>+=</tt> and similar "assignment operators" can be
|
294
|
+
used but are not atomic, because
|
295
|
+
</p>
|
296
|
+
<pre>
|
297
|
+
db[<path>] += 1
|
298
|
+
</pre>
|
299
|
+
<p>
|
300
|
+
is really
|
301
|
+
</p>
|
302
|
+
<pre>
|
303
|
+
db[<path>] = db[<path>] + 1
|
304
|
+
</pre>
|
305
|
+
<p>
|
306
|
+
So another thread or process could change the value stored at <tt>path</tt>
|
307
|
+
while the addition is happening.
|
308
|
+
</p>
|
309
|
+
</li>
|
310
|
+
<li>Transactions that allow more complex interaction:
|
311
|
+
|
312
|
+
<pre>
|
313
|
+
path = 'foo/bar'
|
314
|
+
db[path] = [1,2,3]
|
315
|
+
|
316
|
+
db.edit path do |bar|
|
317
|
+
bar += [4]
|
318
|
+
bar[-1]
|
319
|
+
end
|
320
|
+
</pre>
|
321
|
+
<p>
|
322
|
+
This guarantees that, if the object at the path is still <tt>[1, 2, 3]</tt>
|
323
|
+
at the time of the edit call, the value returned by the transaction will be
|
324
|
+
+4+.
|
325
|
+
</p>
|
326
|
+
<p>
|
327
|
+
Simply put, edit allows exclusive write access to the object at the path
|
328
|
+
for the duration of the block. Other threads or processes that use <a
|
329
|
+
href="../classes/FSDB.html">FSDB</a> methods to read or write the object
|
330
|
+
will be blocked for the duration of the transaction. There is also browse,
|
331
|
+
which allows read access shared by any number of threads and processes, and
|
332
|
+
replace, which also allows exclusive write access like edit. The
|
333
|
+
differences between replace and edit are:
|
334
|
+
</p>
|
335
|
+
<ul>
|
336
|
+
<li>replace’s block must return the new value, whereas edit’s block
|
337
|
+
must operate (destructively) on the block argument to produce the new
|
338
|
+
value. (The new value in replace’s block can be a modification of the
|
339
|
+
old value, or an entirely different object.)
|
340
|
+
|
341
|
+
</li>
|
342
|
+
<li>replace yields <tt>nil</tt> if there is no preexisting object, whereas edit
|
343
|
+
calls default_edit (which by default calls object_missing, which by default
|
344
|
+
throws MissingObjectError).
|
345
|
+
|
346
|
+
</li>
|
347
|
+
<li>edit is useless over a drb connection, since is it operating on a
|
348
|
+
Marshal.dump-ed copy. Use replace with drb.
|
349
|
+
|
350
|
+
</li>
|
351
|
+
</ul>
|
352
|
+
<p>
|
353
|
+
You can delete an object from the database (and the file system) with
|
354
|
+
delete, which returns the object. Also, delete can take a block, which can
|
355
|
+
examine the object and abort the transaction to prevent deletion. (The
|
356
|
+
delete transaction has the same exclusion semantics as edit and replace.)
|
357
|
+
</p>
|
358
|
+
<p>
|
359
|
+
The fetch and insert methods are aliased with <tt>[ ]</tt> and <tt>[
|
360
|
+
]=</tt>.
|
361
|
+
</p>
|
362
|
+
<p>
|
363
|
+
When the object at the path specified in a transaction does not exist in
|
364
|
+
the file system, the different transaction methods behave differently:
|
365
|
+
</p>
|
366
|
+
<ul>
|
367
|
+
<li>browse calls default_browse, which, in Database’s implementation,
|
368
|
+
calls object_missing, which raises Database::MissingObjectError.
|
369
|
+
|
370
|
+
</li>
|
371
|
+
<li>edit calls default_edit, which, in Database’s implementation, calls
|
372
|
+
object_missing, which raises Database::MissingObjectError.
|
373
|
+
|
374
|
+
</li>
|
375
|
+
<li>replace and insert (and #[]) ignore any missing file.
|
376
|
+
|
377
|
+
</li>
|
378
|
+
<li>delete does nothing (if you want, you can detect the fact that the object
|
379
|
+
is missing by checking for nil in the block argument).
|
380
|
+
|
381
|
+
</li>
|
382
|
+
<li>fetch calls default_fetch, which, in Database’s implementation,
|
383
|
+
returns nil.
|
384
|
+
|
385
|
+
</li>
|
386
|
+
</ul>
|
387
|
+
<p>
|
388
|
+
Transactions can be nested. However, the order in which objects are locked
|
389
|
+
can lead to deadlock if, for example, the nesting is cyclic, or two threads
|
390
|
+
or processes request the same set of locks in a different order. One
|
391
|
+
approach is to only request nested locks on paths in the lexicographic
|
392
|
+
order of the path strings: "foo/bar", "foo/baz",
|
393
|
+
…
|
394
|
+
</p>
|
395
|
+
<p>
|
396
|
+
A transaction can be aborted with Database#abort and Database.abort, after
|
397
|
+
which the state of the object in the database remains as before the
|
398
|
+
transaction. An exception that is raised but not handled within a
|
399
|
+
transaction also aborts the transaction.
|
400
|
+
</p>
|
401
|
+
<p>
|
402
|
+
Note that there is no locking on directories, but you can designate a lock
|
403
|
+
file for each dir and effectively have multiple-reader, single writer
|
404
|
+
(advisory) locking on dirs. Just make sure you enclose your dir operation
|
405
|
+
in a transaction on the lock object, and always access these objects using
|
406
|
+
this technique.
|
407
|
+
</p>
|
408
|
+
<pre>
|
409
|
+
db.browse('lock for dir') do
|
410
|
+
db['dir/x'] = 1
|
411
|
+
end
|
412
|
+
</pre>
|
413
|
+
</li>
|
414
|
+
</ul>
|
415
|
+
<h2>Guarding against concurrency problems</h2>
|
416
|
+
<ul>
|
417
|
+
<li>It’s the user’s responsibility to avoid deadlock. See above.
|
418
|
+
|
419
|
+
</li>
|
420
|
+
<li>If you want to fork from a multithreaded process, you should include <a
|
421
|
+
href="../classes/FSDB.html">FSDB</a> or <a
|
422
|
+
href="../classes/FSDB/ForkSafely.html">FSDB::ForkSafely</a>. This prevents
|
423
|
+
"ghost" threads in the child process from permanently holding
|
424
|
+
locks.
|
425
|
+
|
426
|
+
</li>
|
427
|
+
<li>It is not safe to fork while in a transaction.
|
428
|
+
|
429
|
+
</li>
|
430
|
+
<li>A database can be configured to use fcntl locking instead of ruby’s
|
431
|
+
usual flock call. This is necessary for Linux NFS, for example. There
|
432
|
+
doesn’t seem to be any performance difference when running on a local
|
433
|
+
filesystem.
|
434
|
+
|
435
|
+
</li>
|
436
|
+
</ul>
|
437
|
+
<h2>Limitations</h2>
|
438
|
+
<ul>
|
439
|
+
<li>Transactions are not journaled. There’s no commit, undo, or
|
440
|
+
versioning. (You can abort a transaction, however.) These could be
|
441
|
+
added…
|
442
|
+
|
443
|
+
</li>
|
444
|
+
</ul>
|
445
|
+
<h2>Testing</h2>
|
446
|
+
<p>
|
447
|
+
<a href="../classes/FSDB.html">FSDB</a> has been tested on the following
|
448
|
+
platforms and file systems:
|
449
|
+
</p>
|
450
|
+
<pre>
|
451
|
+
- Linux/x86 (single and dual cpu, ext3fs and reiserfs)
|
452
|
+
|
453
|
+
- Solaris/sparc (dual and quad cpu, nfs and ufs)
|
454
|
+
|
455
|
+
- QNX 6.2.1 (dual PIII)
|
456
|
+
|
457
|
+
- Windows 2000 (dual cpu, NTFS)
|
458
|
+
|
459
|
+
- Windows ME (single cpu, FAT32)
|
460
|
+
</pre>
|
461
|
+
<p>
|
462
|
+
<a href="../classes/FSDB.html">FSDB</a> is currently tested with ruby-1.9.0
|
463
|
+
and ruby-1.8.1.
|
464
|
+
</p>
|
465
|
+
<p>
|
466
|
+
On windows, both the mswin32 and mingw32 builds of ruby have been used with
|
467
|
+
<a href="../classes/FSDB.html">FSDB</a>. It has never been tested with
|
468
|
+
cygwin or bccwin.
|
469
|
+
</p>
|
470
|
+
<p>
|
471
|
+
The tests include unit and stress tests. Unit tests isolate individual
|
472
|
+
features of the library. The stress test (called test/test-concurrency.rb)
|
473
|
+
has many parameters, but typically involves several processes, each with
|
474
|
+
several threads, doing millions of transactions on a small set of objects.
|
475
|
+
</p>
|
476
|
+
<p>
|
477
|
+
The only known testing failure is on Windows ME (and presumably 95 and 98).
|
478
|
+
The stress test succeeds with one process and multiple threads. It succeeds
|
479
|
+
with multiple processes each with one thread. However, with two processes
|
480
|
+
each with two threads, the test usually deadlocks very quickly.
|
481
|
+
</p>
|
482
|
+
<h2>Performance</h2>
|
483
|
+
<p>
|
484
|
+
<a href="../classes/FSDB.html">FSDB</a> is not very fast. It’s useful
|
485
|
+
more for its safety, flexibility, and ease of use.
|
486
|
+
</p>
|
487
|
+
<ul>
|
488
|
+
<li><a href="../classes/FSDB.html">FSDB</a> operates on cached data as much as
|
489
|
+
possible. In order to be process safe, changing an object (with edit,
|
490
|
+
replace, insert) results in a dump of the object to the file system. This
|
491
|
+
includes marshalling or other custom serialization to a string, as well as
|
492
|
+
a syswrite call. The file system buffers may keep the latter part from
|
493
|
+
being too costly, but the former part can be costly, especially for complex
|
494
|
+
objects. By using either custom marshal methods, or nonpersistent attrs
|
495
|
+
where possible (see nonpersistent-attr.rb), or <a
|
496
|
+
href="../classes/FSDB.html">FSDB</a> dump/load methods that use a faster
|
497
|
+
format (e.g., plain text, rather than a marshalled String), this may not be
|
498
|
+
so bad.
|
499
|
+
|
500
|
+
</li>
|
501
|
+
<li>On an 850MHz PIII under linux, with debugging turned off (-b option),
|
502
|
+
test-concurrency.rb reports:
|
503
|
+
|
504
|
+
<pre>
|
505
|
+
processes threads objects transactions per cpu second
|
506
|
+
---------------------------------------------------------------
|
507
|
+
1 1 10 965
|
508
|
+
1 10 10 165
|
509
|
+
10 1 10 684
|
510
|
+
10 10 10 122
|
511
|
+
10 10 100 100
|
512
|
+
10 10 10000 92
|
513
|
+
</pre>
|
514
|
+
<p>
|
515
|
+
These results are not representative of typical applications, because the
|
516
|
+
test was designed to stress the database and expose stability problems, not
|
517
|
+
to immitate typical use of database-stored objects. See bench/bench.rb for
|
518
|
+
for bechmarks.
|
519
|
+
</p>
|
520
|
+
</li>
|
521
|
+
<li>For speed, avoid using fetch and its alias #[]. As noted in the API docs,
|
522
|
+
these methods cannot safely return the same object that is cached, so must
|
523
|
+
clear out the cache’s reference to the object so that is will be
|
524
|
+
loaded freshly the next time fetch is called on the path.
|
525
|
+
|
526
|
+
<p>
|
527
|
+
The performance hit of fetch is of course greater with larger objects, and
|
528
|
+
with objects that are loaded by a more complex procedure, such as
|
529
|
+
Masrshal.load.
|
530
|
+
</p>
|
531
|
+
<p>
|
532
|
+
You can think of fetch as a "deep copy" of the object. If you
|
533
|
+
call it twice, you get different copies that do not share any parts. Or you
|
534
|
+
can think of it as File.read—it gives you an instantaneous snapshot
|
535
|
+
of the file, but does not give you a transaction "window" in
|
536
|
+
which no other thread or process can modify the object.
|
537
|
+
</p>
|
538
|
+
<p>
|
539
|
+
There is no analogous concern with insert and its alias #[]=. These methods
|
540
|
+
always write to the file system, but they also leave the object in the
|
541
|
+
cache.
|
542
|
+
</p>
|
543
|
+
</li>
|
544
|
+
<li>Performance is worse on Windows. Most of the delay seems to be in system,
|
545
|
+
rather than user, code.
|
546
|
+
|
547
|
+
</li>
|
548
|
+
</ul>
|
549
|
+
<h2>Advantages</h2>
|
550
|
+
<ul>
|
551
|
+
<li><a href="../classes/FSDB.html">FSDB</a> is useful with heterogeneous data,
|
552
|
+
that is, with files in varying formats that can be recognized based on file
|
553
|
+
name.
|
554
|
+
|
555
|
+
</li>
|
556
|
+
<li><a href="../classes/FSDB.html">FSDB</a> can be used as an interface to the
|
557
|
+
file system that understands file types. By defining new format clases,
|
558
|
+
it’s easy to set up databases that allow:
|
559
|
+
|
560
|
+
<pre>
|
561
|
+
home['.forward'] += ["nobody@nowhere.net"]
|
562
|
+
etc.edit('passwd') { |passwd| passwd['fred'].shell = '/bin/zsh' }
|
563
|
+
window.setIcon(icons['apps/editor.png'])
|
564
|
+
</pre>
|
565
|
+
</li>
|
566
|
+
<li>A <a href="../classes/FSDB.html">FSDB</a> can be operated on with ordinary
|
567
|
+
file tools. <a href="../classes/FSDB.html">FSDB</a> can even treat existing
|
568
|
+
file hierarchies as databases. It’s easy to backup, export, grep,
|
569
|
+
… the database. Its just files.
|
570
|
+
|
571
|
+
</li>
|
572
|
+
<li><a href="../classes/FSDB.html">FSDB</a> is process-safe, so it can be used
|
573
|
+
for <b>persistent</b>, *fault-tolerant* interprocess communication, such as
|
574
|
+
a queue that doesn’t require both processes to be alive at the same
|
575
|
+
time. It’s a good way to safely connect a suite of applications that
|
576
|
+
share common files. Also, you can take advantage of multiprocessor systems
|
577
|
+
by forking a new process to handle a CPU-intesive transaction.
|
578
|
+
|
579
|
+
</li>
|
580
|
+
<li><a href="../classes/FSDB.html">FSDB</a> is thread-safe, so it can be used
|
581
|
+
in a threaded server, such as drb. In fact, the <a
|
582
|
+
href="../classes/FSDB.html">FSDB</a> Database itself can be the drb server
|
583
|
+
object, allowing browse, replace (but not edit), insert, and delete from
|
584
|
+
remote clients! (See the examples server.rb and client.rb.)
|
585
|
+
|
586
|
+
</li>
|
587
|
+
<li><a href="../classes/FSDB.html">FSDB</a> can be used as a portable interface
|
588
|
+
to multithreaded file locking. (File#flock does not have consistent
|
589
|
+
semantics across platforms.)
|
590
|
+
|
591
|
+
</li>
|
592
|
+
<li>Compared with PStore, <a href="../classes/FSDB.html">FSDB</a> has the
|
593
|
+
potential for finer granularity, and it scales better. The cost of using
|
594
|
+
fine granularity is that referential structures, unless contained within
|
595
|
+
individual nodes, must be based on path strings. (But of course this would
|
596
|
+
be a problem with multiple PStores, as well.)
|
597
|
+
|
598
|
+
</li>
|
599
|
+
<li><a href="../classes/FSDB.html">FSDB</a> scales up to large numbers of
|
600
|
+
objects.
|
601
|
+
|
602
|
+
</li>
|
603
|
+
<li>Objects in a <a href="../classes/FSDB.html">FSDB</a> can be anything
|
604
|
+
serializable. They don’t have to inherit or mix in anything.
|
605
|
+
|
606
|
+
</li>
|
607
|
+
<li>By using only the file system and standard ruby libraries, installation
|
608
|
+
requirements are minimal.
|
609
|
+
|
610
|
+
</li>
|
611
|
+
<li>It may be fast enough for many purposes, especially using multiple
|
612
|
+
processes rather than multiple threads.
|
613
|
+
|
614
|
+
</li>
|
615
|
+
<li>Pure ruby. Ruby license. Free sotware.
|
616
|
+
|
617
|
+
</li>
|
618
|
+
</ul>
|
619
|
+
<h2>Applications</h2>
|
620
|
+
<p>
|
621
|
+
I’ve heard from a couple of people writing applications that use <a
|
622
|
+
href="../classes/FSDB.html">FSDB</a>. One app is:
|
623
|
+
</p>
|
624
|
+
<ul>
|
625
|
+
<li><a href="http://tourneybot.rubyforge.org">tourneybot.rubyforge.org</a>
|
626
|
+
|
627
|
+
</li>
|
628
|
+
</ul>
|
629
|
+
<h2>To do</h2>
|
630
|
+
<h3>Fix (potential) bugs</h3>
|
631
|
+
<ul>
|
632
|
+
<li>If two FSDBs are in use in the same process, they share the cache. If they
|
633
|
+
associate different formats with the same file, the results will be
|
634
|
+
surprising. Maybe the cache should remember the format used and flag an
|
635
|
+
error if it detects an inconsistency. A similar problem could happen for
|
636
|
+
other Database attributes, like lock-type (which should probably be
|
637
|
+
global).
|
638
|
+
|
639
|
+
</li>
|
640
|
+
</ul>
|
641
|
+
<h3>Features</h3>
|
642
|
+
<ul>
|
643
|
+
<li>Should the Format objects be classes instead of just instances of Format?
|
644
|
+
|
645
|
+
</li>
|
646
|
+
<li>Default value and proc for Database, like Hash.
|
647
|
+
|
648
|
+
</li>
|
649
|
+
<li>FSDB::Reference class:
|
650
|
+
|
651
|
+
<pre>
|
652
|
+
db['foo/bar.obj'] = "some string"
|
653
|
+
referrer = { :my_bar => FSDB::Reference.new('../foo/bar.obj') }
|
654
|
+
db['x/y.yml'] = referrer
|
655
|
+
p db['x/y.yml'][:my_bar] # ==> "some string"
|
656
|
+
</pre>
|
657
|
+
<p>
|
658
|
+
Or, more like DRbUndumped:
|
659
|
+
</p>
|
660
|
+
<pre>
|
661
|
+
str = "some string"
|
662
|
+
str.extend FSDB::Undumped
|
663
|
+
db['foo/bar.obj'] = str
|
664
|
+
referrer = { :my_bar => str }
|
665
|
+
db['x/y.yml'] = referrer
|
666
|
+
p db['x/y.yml'][:my_bar] # ==> "some string"
|
667
|
+
</pre>
|
668
|
+
<p>
|
669
|
+
Extending with FSDB::Undumped will have to insert state in the object that
|
670
|
+
remembers the db path at which it is stored (‘foo/bar.obj’ in
|
671
|
+
this case).
|
672
|
+
</p>
|
673
|
+
</li>
|
674
|
+
<li>Use (optionally) weak references in CacheEntry.
|
675
|
+
|
676
|
+
</li>
|
677
|
+
<li>use metafiles to emulate locking on dirs?
|
678
|
+
|
679
|
+
</li>
|
680
|
+
<li>optionally, for each file, store a md5 sum of the raw data, so that we may
|
681
|
+
be able to avoid Marshal.load and (after dump) the actual write.
|
682
|
+
|
683
|
+
</li>
|
684
|
+
<li>optionally, do not create ..fsdb.meta.* files.
|
685
|
+
|
686
|
+
</li>
|
687
|
+
<li>transactions on groups of objects
|
688
|
+
|
689
|
+
<ul>
|
690
|
+
<li>for edit and browse, but not replace or insert. Maybe delete.
|
691
|
+
|
692
|
+
</li>
|
693
|
+
<li>db.edit [path1, path2] do |obj1, obj2| … end
|
694
|
+
|
695
|
+
<ul>
|
696
|
+
<li>lock order is explicit, up to user to avoid deadlock
|
697
|
+
|
698
|
+
</li>
|
699
|
+
</ul>
|
700
|
+
</li>
|
701
|
+
<li>db.edit_glob "foo/**/bar*/{zap,zow}" … do |hash|
|
702
|
+
|
703
|
+
<pre>
|
704
|
+
for path, object in hash ... end
|
705
|
+
</pre>
|
706
|
+
<p>
|
707
|
+
end
|
708
|
+
</p>
|
709
|
+
</li>
|
710
|
+
</ul>
|
711
|
+
</li>
|
712
|
+
<li>Make irb-based database shell
|
713
|
+
|
714
|
+
<ul>
|
715
|
+
<li>class Database; def irb_browse(path); browse(path) {|obj| irb obj}; end;
|
716
|
+
end
|
717
|
+
|
718
|
+
<p>
|
719
|
+
then:
|
720
|
+
</p>
|
721
|
+
<pre>
|
722
|
+
irb> irb db
|
723
|
+
irb#1> irb_browse path
|
724
|
+
...
|
725
|
+
... # got a read lock for this session
|
726
|
+
...
|
727
|
+
irb#1> ^D
|
728
|
+
irb>
|
729
|
+
</pre>
|
730
|
+
<p>
|
731
|
+
one problem: irb defines singleton methods, so can’t dump (in edit)
|
732
|
+
</p>
|
733
|
+
<p>
|
734
|
+
maybe we can extend the class of the object by some module instead…
|
735
|
+
</p>
|
736
|
+
</li>
|
737
|
+
</ul>
|
738
|
+
</li>
|
739
|
+
<li>iterator, query, indexing methods
|
740
|
+
|
741
|
+
</li>
|
742
|
+
<li>more formats
|
743
|
+
|
744
|
+
<ul>
|
745
|
+
<li>tabular data, excel, xml, ascii db, csv
|
746
|
+
|
747
|
+
</li>
|
748
|
+
<li>SOAP marshal, XML marshal
|
749
|
+
|
750
|
+
</li>
|
751
|
+
<li>filters for compression, encryption
|
752
|
+
|
753
|
+
</li>
|
754
|
+
</ul>
|
755
|
+
</li>
|
756
|
+
<li>more node types
|
757
|
+
|
758
|
+
<pre>
|
759
|
+
.que : use IO#read_object, IO#write_object (at end of file)
|
760
|
+
to implement a persistent queue
|
761
|
+
|
762
|
+
fifo, named socket, device, ...
|
763
|
+
</pre>
|
764
|
+
</li>
|
765
|
+
<li>interface to file attributes (mode, etc)
|
766
|
+
|
767
|
+
</li>
|
768
|
+
<li>access control lists (use meta files)
|
769
|
+
|
770
|
+
</li>
|
771
|
+
</ul>
|
772
|
+
<h3>Stability, Security, and Error Checking</h3>
|
773
|
+
<ul>
|
774
|
+
<li>investigate using the BDB lock mechanism in place of flock.
|
775
|
+
|
776
|
+
</li>
|
777
|
+
<li>in transactions, if path is tainted, apply the validation of util.rb?
|
778
|
+
|
779
|
+
</li>
|
780
|
+
<li>detect fork in transaction
|
781
|
+
|
782
|
+
</li>
|
783
|
+
<li>purge empty dirs?
|
784
|
+
|
785
|
+
</li>
|
786
|
+
<li>periodically clear_cache to keep the hash size low
|
787
|
+
|
788
|
+
<ul>
|
789
|
+
<li>every Nth new CacheEntry?
|
790
|
+
|
791
|
+
</li>
|
792
|
+
<li>should cache entries be in an LRU queue so we can purge the LRU?
|
793
|
+
|
794
|
+
</li>
|
795
|
+
</ul>
|
796
|
+
</li>
|
797
|
+
<li>should we detect recursive lock attempt and fail? (Now, it just deadlocks.)
|
798
|
+
|
799
|
+
</li>
|
800
|
+
</ul>
|
801
|
+
<h3>Performance</h3>
|
802
|
+
<ul>
|
803
|
+
<li>Profiling says that Thread.exclusive consumes about 20% of cpu. Also,
|
804
|
+
Thread.stop and Thread.run when there are multiple threads. Using
|
805
|
+
Thread.critical in places where it is safe to do so (no exceptions raised)
|
806
|
+
instead of Thread.exclusive would reduce this to an estimated 6%. ((See
|
807
|
+
faster-modex .rb and faster-mutex.rb.))
|
808
|
+
|
809
|
+
</li>
|
810
|
+
<li>Better way of waiting for file lock in the multithread case
|
811
|
+
|
812
|
+
<ul>
|
813
|
+
<li>this may be unfixable until ruby has native threads
|
814
|
+
|
815
|
+
</li>
|
816
|
+
</ul>
|
817
|
+
</li>
|
818
|
+
<li>Use shared memory for the cache, so write is not necessary after edit.
|
819
|
+
|
820
|
+
<ul>
|
821
|
+
<li>actually, this may not make much sense
|
822
|
+
|
823
|
+
</li>
|
824
|
+
</ul>
|
825
|
+
</li>
|
826
|
+
<li>Option for Database to ignore file locking and possibility of other
|
827
|
+
writers.
|
828
|
+
|
829
|
+
</li>
|
830
|
+
<li>fetch could use the cache better if the cache kept the file contents string
|
831
|
+
as well as the loaded object. Then the stale! call would only have to wipe
|
832
|
+
the reference to the object, and could leave the contents string. But this
|
833
|
+
would increase file size and duplicate the file system’s own cache.
|
834
|
+
|
835
|
+
</li>
|
836
|
+
</ul>
|
837
|
+
<h2>Version</h2>
|
838
|
+
<p>
|
839
|
+
fsdb 0.5
|
840
|
+
</p>
|
841
|
+
<p>
|
842
|
+
The current version of this software can be found at <a
|
843
|
+
href="http://redshift.sourceforge.net/fsdb">redshift.sourceforge.net/fsdb</a>.
|
844
|
+
</p>
|
845
|
+
<h2>License</h2>
|
846
|
+
<p>
|
847
|
+
This software is distributed under the Ruby license. See <a
|
848
|
+
href="http://www.ruby-lang.org">www.ruby-lang.org</a>.
|
849
|
+
</p>
|
850
|
+
<h2>Author</h2>
|
851
|
+
<p>
|
852
|
+
Joel VanderWerf, <a
|
853
|
+
href="mailto:vjoel@users.sourceforge.net">vjoel@users.sourceforge.net</a>
|
854
|
+
Copyright © 2005, Joel VanderWerf.
|
855
|
+
</p>
|
856
|
+
|
857
|
+
</div>
|
858
|
+
|
859
|
+
|
860
|
+
</div>
|
861
|
+
|
862
|
+
|
863
|
+
</div>
|
864
|
+
|
865
|
+
|
866
|
+
<!-- if includes -->
|
867
|
+
|
868
|
+
<div id="section">
|
869
|
+
|
870
|
+
|
871
|
+
|
872
|
+
|
873
|
+
|
874
|
+
|
875
|
+
|
876
|
+
|
877
|
+
<!-- if method_list -->
|
878
|
+
|
879
|
+
|
880
|
+
</div>
|
881
|
+
|
882
|
+
|
883
|
+
<div id="validator-badges">
|
884
|
+
<p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
|
885
|
+
</div>
|
886
|
+
|
887
|
+
</body>
|
888
|
+
</html>
|