Page 1 of 1
Transaction Based File System Operations
Posted: Fri Jul 27, 2007 6:18 am
by Ollie Saunders
I want to have the equivalent of rollback and commit for file system operations.
Here's my idea: addAction() buffers actions; each action is a separate small class. The commit method performs the actual actions, in order, and throws an exception if there is failure. The exception thrown can to be passed a rollback() method.
Several try catch blocks wrapped in one overall large try catch can be used to continue despite failure selectively:
Code: Select all
$inst = new FsTrans();
try {
$inst->addAction('NewDir', array('foo'));
try {
$inst->addAction('SetPermissions', array('foo', 0777));
$inst->commit();
} catch (FsTrans_Exception $e) {
echo "Failed to set directory permissions on foo\n";
// continuing...
}
$inst->addAction('ChangeDir', array('foo'));
$inst->addAction('NewFile', array('bar.txt', 'bar'));
$inst->commit();
} catch (FsTrans_Exception $e) {
$inst->rollback();
}
Has this ever been written before? Can anyone point me to an existing library?
How do you suggest I unit test this? Am I going to have to setUp() certain file/directory structures to run this in and tearDown() them after. I've written things like that before and they get pretty damn confusing. Finally, how could I make code that uses this testable?
Posted: Fri Jul 27, 2007 10:34 am
by McGruff
If you check out the Aperiplus link below there's a FileSystemTestCase (an extension for SimpleTest). Depending how complicated it gets there might or might not be some objects to mock but you'll definitely want to test using a real filesystem at some point.
Setting up and tearing down directory structures for each test won't present any problems unless you've got a very old machine. If you need complex fixtures the usual extract method, extract class stuff will keep them under control. It sometimes helps to write new expectation classes - or even new test cases. I'll always drop what I'm doing to write new testing tools if that's what's needed to keep things readable.
But how do you know you want to use try/catch...? What's the first test you would write using the language of the domain?
Posted: Fri Jul 27, 2007 12:58 pm
by Chris Corbyn
You could probably write a custom fake file stream without creating real files too.
Posted: Fri Jul 27, 2007 2:44 pm
by Ambush Commander
Hey McGruff! Nice to see you around!
Unless you are performing an integration test, testing the above code shouldn't require any monkeying around with the filesystem: simply mock FsTrans and be done with it! I don't believe SimpleTest currently supports throwing exceptions from mocks when certain conditions are met, so you may need to custom code it yourself.
Testing FsTran, and testing the whole kaboodle, however, is another business, and I go with directly manipulating the filesystem. It's not too difficult to do, although make sure you're able to recursively delete directories and check the filesystem state before doing any writing.
Posted: Fri Jul 27, 2007 3:52 pm
by Ollie Saunders
If you check out the Aperiplus link below there's a FileSystemTestCase
Actually I have had a glance over the source of that, thanks for the reminder that could be useful. Although there's a ShellTestCase that comes with SimpleTest as well.
You could probably write a custom fake file stream without creating real files too.
Ooh that's interesting how do you do that? I've basically very little/no experience of streams.
Posted: Fri Jul 27, 2007 6:50 pm
by timvw
Why don't you simply use a filesystem that supports transactions? (eg: Windows Vista has one *grin* and an API...)
Posted: Sat Jul 28, 2007 9:23 am
by programmingjeff
timvw wrote:Why don't you simply use a filesystem that supports transactions? (eg: Windows Vista has one *grin* and an API...)
If he were to depend on Vista, the install base for his application would be severely limited.
The concept of streams are called "Named Pipes" in Linux. You read & write to them using the same set of functions that you use for file I/O. I believe that you would write all of your filesystem transaction information to the pipe, and then reread & execute it when you want to commit. This implementation would be nothing more than a complicated buffer.
A simple google search turns up some good introduction tutorials for how to use pipes (although not for PHP).
Posted: Sat Jul 28, 2007 10:25 am
by McGruff
Ambush Commander wrote:Hey McGruff! Nice to see you around!
Hi. Unfortunately I don't have much time for programming these days. If I could only photosynthesise I'd be free to spend my life doing what I like. Getting money to eat takes up too much thinking time.
streams:
I'm not sure if this would do the trick. You could test file reads and writes but what about creates and deletes? You'll probably need to create/delete dirs as well as files but I don't know that yet.
To be honest I don't really like talking about code without tests since you can easily end up making something more complicated than it needs to be. What is the first test? In which class did the need for filesystem transactions originally emerge?