Transaction Based File System Operations

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Transaction Based File System Operations

Post 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?
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post 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?
User avatar
Chris Corbyn
Breakbeat Nuttzer
Posts: 13098
Joined: Wed Mar 24, 2004 7:57 am
Location: Melbourne, Australia

Post by Chris Corbyn »

You could probably write a custom fake file stream without creating real files too.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post 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.
User avatar
Ollie Saunders
DevNet Master
Posts: 3179
Joined: Tue May 24, 2005 6:01 pm
Location: UK

Post 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.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

Why don't you simply use a filesystem that supports transactions? (eg: Windows Vista has one *grin* and an API...)
programmingjeff
Forum Commoner
Posts: 26
Joined: Fri Jan 05, 2007 10:56 am

Post 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).
McGruff
DevNet Master
Posts: 2893
Joined: Thu Jan 30, 2003 8:26 pm
Location: Glasgow, Scotland

Post 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?
Post Reply