Once you have a repository, you need to create a file. This is a two step
process. The first step is to register the file. To do this, you define the
file's name and pass it to Repository::createFile()
,
which returns the fileid
of the created file. At this point,
the file is registered in the system, but there's nothing actually in the file
system.
You operate on files in the repository using
JW::DMS::File
objects. These are standard Ruby
File
objects which are extended to incorporate the
necessary locking, transaction, and path management facilities used in the
system. You open a DMS file like you do a normal Ruby file, but rather than
specifying a file name, you provide the fileid
. The whole
process of creating and opening a file is as follows:
fileid = dms.createFile('README.TXT') file = dms.openFile(fileid, 'w')
The second argument to openFile()
is the file mode,
just like the standard Ruby File::open()
call, where
you specify read/write access. Depending on the mode, the respository will
obtain the requisite locks. The locking implementation simply ensures that there
can only be one File
object open with write access to a
file at a time. There are two basic locks: shared and exclusive. File objects
open in read obtain a shared lock. A file object opening for write obtains an
exclusive lock. Thus, there can be multiple readers, but only one writer.
The locking system is implemented using PostgreSQL advisory locks. Rather
than using actual filesystem locks, all file access is coordinated from the
database. The advantage here is that if an exception is encountered, any locks
can be easily cleared by a single call to the database, whereas it might be more
difficult to track down any particular file locks which may have been
issued. All that is required for DMS is to call
Repository.unlockAll()
, which releases all locks
acquired by a given Repository
object. The other
advantage is that since the locking implementation is in PostgreSQL, you can
host the file store anywhere (including distributed file systems like NFS and
Samba) and locking will work just as reliably.
Once you obtain the file object, you operate on it exactly as you would a
Ruby file. The only difference is that when you call
close()
, the File
object will
update the system metadata fields (e.g. size
,
hash
, mtime
, etc.). before it closes the
actual file system handle.