AthenaeumAthenaeum
Packages
  • next
  • current
  • v9.x
  • v8.x
  • v7.x
  • v6.x
  • v5.x
  • v4.x
  • v3.x
  • v2.x
  • v1.x
Changelog
GitHub
Packages
  • next
  • current
  • v9.x
  • v8.x
  • v7.x
  • v6.x
  • v5.x
  • v4.x
  • v3.x
  • v2.x
  • v1.x
Changelog
GitHub
  • Version 6.x

    • Release Notes
    • Upgrade Guide
    • New to this...
    • Contribution Guide
    • Security Policy
    • Code of Conduct
    • Origin
  • ACL

    • Introduction
    • How to install
    • Setup
    • Permissions
    • Roles
    • Users
    • Cached Permissions
  • Audit

    • Audit
    • How to install
    • Setup
    • Recording
    • Events
  • Circuits

    • Circuits
    • How to install
    • Setup
    • Usage
    • Events
  • Collections

    • Collections
    • How to install
    • Summation

      • Summation Collection
      • Items Processor
  • Config

    • Configuration Loader
    • How to install
    • Setup
    • Load Configuration Files
    • Custom File Parsers
  • Console

    • Command and Schedule Registration
    • How to install
    • Setup
    • Commands
    • Schedules
  • Container

    • IoC Service Container
    • How to install
    • Container
    • List Resolver
  • Core

    • Athenaeum Core Application
    • How to install
    • Setup
    • Usage

      • Configuration
      • Service Providers
      • Service Container
      • Events
      • Caching
      • Logging
      • Console
      • Task Scheduling
      • Exception Handling
      • Extending Core Application
      • Testing
  • Database

    • Introduction
    • How to install
    • Models

      • Instantiatable
      • Sluggable
    • Query

      • Criteria (Query Filter)
  • Dto

    • Data Transfer Object (DTO)
    • How to install
    • Create Interface
    • Implement DTO
    • How to use
    • Populate
    • Export
    • Json
    • Serialization
    • Nested DTOs
    • Array DTO
  • ETags

    • ETags
    • How to install
    • Setup
    • Usage
    • Generators

      • Default Generator
      • Custom Generator
    • Eloquent Models
    • Macros
  • Events

    • Register Listeners and Subscribers
    • How to install
    • Setup
    • Listeners
    • Subscribers
  • Filters

    • Search Filter Utilities
    • Prerequisites
    • How to install
    • Setup
    • Processor
    • Filters Builder
    • Predefined Resources

      • Search Processor
      • Sorting Processor
      • Constraints Processor
      • Matching Processor
    • Tip: Create a base builder
  • Flysystem

    • Introduction
    • Database Adapter

      • Introduction
      • How to install
      • Setup
      • Data Deduplication
      • MIME-Type Detection
  • Http

    • Api

      • Http API
      • How to install
      • Setup
      • Resources

        • Introduction
        • Timestamps
        • Self-Link
        • Relations
        • Registrar
      • Middleware

        • Introduction
        • Request Must Be Json
        • Capture Fields To Select
    • Clients

      • Http Clients
      • How to install
      • Setup
      • Basic Usage
      • Available Methods

        • Fluent Api
        • Protocol Version
        • Base Uri
        • Http Method and Uri
        • Headers
        • Accept & Content-Type
        • Authentication
        • Http Query
        • Payload Format
        • Payload
        • Attachments
        • Cookies
        • Response Expectations
        • Middleware
        • Conditions
        • Criteria
        • Redirects
        • Timeout
        • Debugging
        • Logging
        • Driver Options
        • Driver
      • Http Query Builder

        • Introduction
        • Select
        • Where
        • Dates
        • Include
        • Pagination
        • Sorting
        • Raw Expressions
        • Custom Grammar
    • Cookies

      • Http Cookies
      • How to install
      • Usage
    • Messages

      • Http Messages
      • How to install
      • Serializers
  • Maintenance

    • Modes

      • Maintenance Modes
      • How to install
      • Setup
      • Basic Usage
      • Available Drivers
  • Mime Types

    • MIME-Types
    • How to install
    • Setup
    • Usage
    • Drivers

      • Available Drivers
      • File Info
  • Properties

    • Properties Overload
    • How to install
    • Usage
    • Naming Convention
    • Properties Visibility
  • Redmine

    • Redmine Api Client
    • How to install
    • Setup
    • General Usage

      • Supported Operations
      • Fetch list of resources
      • Find
      • Fetch
      • Create new record
      • Update existing record
      • Delete existing record
      • Relations
    • Available Resources

      • Predefined Resources
      • Attachments
      • Enumerations
      • Issue Relations
      • Users
      • User Groups
      • Roles
      • Project Memberships
      • Versions (Milestones)
      • Issue Categories
      • Trackers
  • Service

    • Service Registrar
    • How to install
    • How to use
  • Streams

    • Streams
    • How to install
    • Setup
    • How to use

      • Introduction
      • Open and Close
      • Raw Resource
      • Seeking
      • Reading
      • Writing
      • Size
      • Truncate
      • Flush
      • Hash
      • MIME-Type
      • Output
      • Locking
      • Transactions
      • Meta
      • Misc
  • Support

    • Introduction
    • How to install
    • Laravel Aware-of Helpers

      • How to use
      • Enforce Via Interface
      • Custom Default
      • Pros and Cons
      • Available Helpers
    • Aware-of Properties

      • Generator
      • Available Aware-of Helpers
    • Live Templates
  • Testing

    • Introduction
    • How to install
    • Test Cases
    • Testing Aware-of Helpers
  • Utils

    • Introduction
    • How to install
    • Array
    • Duration
    • Json
    • Math
    • Memory
    • Method Helper
    • Invoker
    • Populatable
    • String
    • Version
  • Validation

    • Introduction
    • How to install
    • Setup
    • Rules

      • Alpha-Dash-Dot
      • Semantic Version
You are viewing documentation for an outdated version. It is no longer supported!

Transactions

The FileStream component offers a way to safely perform dangerous operations on a file, by means of a transaction mechanism. In this context, "dangerous operations" means any kind of stream manipulation that can fail.

  • Perform Transaction
  • How it works
    • Begin
    • Process
    • Commit
    • Rollback
  • Backup
  • Customisation
  • Onward

Perform Transaction

The easiest way to perform a transaction on a file stream, is by using the transaction() method. It accepts the following arguments:

  • callable $operation: Operation callback. A Stream instance is given as callback's argument.
  • int $attempts: (optional) Maximum amount of attempts to perform operation. Defaults to 1.
  • string|null $profile: (optional) Transaction profile driver to use (see Customisation for details).
  • array $options: (optional) Transaction driver specific options (see Customisation for details).

The following shows a simplified example, in which some content is appended to a file.

$stream = FileStream::open('orders.txt', 'r+b');

$result = $stream->transaction(function($stream) {
    // Add or change content in given stream
    $stream
        ->append("\nT-shirt     Large       4.99 EUR")
        ->append("\nT-shirt     Small       4.45 EUR")
        ->append("\nT-shirt     Extra Large 5.15 EUR");
    
    // Return eventual result (optional)
    return (string) $stream;
});

How it works

When the transaction() method is invoked, then the following process is performed:

Begin

  1. The target stream is locked using an exclusive lock.
  2. Target stream is backed up, if such configured (see backup for details).
  3. A new copy is created (processing stream) of the target stream, using a temporary stream.

Process

  1. The callback is invoked using given the processing stream as argument.

Commit

  1. After the callback has completed, the changes are committed; target stream's content is overwritten with content from the processing stream.
  2. Backup-file is removed, if such configured (see backup for details).
  3. Target stream's lock is released and evt. output from callback is returned.

Rollback

  • In case of failure, rollback and retry if more attempt are available. Rollback is performed by resetting the process stream and (re)copying target stream's content into it. Backup file is NOT used for rolling back!
  • When no more attempts are available, release the lock and allow exception to bubble upwards

As you can see, this is not a simple process and many things can go wrong during a transaction. It is therefore highly RECOMMENDED that you enable backup, if you use transactions in a production environment.

Furthermore, you should expect that working with this kind of transactions can be memory and I/O intensive.

Backup

Warning

Backup of the target stream is NOT ENABLED, by the default transaction "profile". Without any additional configuration or customisation, no backup is made.

Backup can be configured in your config/streams.php configuration file, when situated within a regular Laravel application. However, you can always overwrite the profile's "backup" configuration using the $options argument, in the transaction() method, regardless of what profile is used.

$stream = FileStream::open('orders.txt', 'r+b');

// Custom options
$options = [
    'backup' => [

        // When true, a backup of target stream (*.bak file) will be stored
        'enabled' => true,

        // Location of backup files
        'directory' => getcwd() . DIRECTORY_SEPARATOR . 'my_file_backups',

        // When true, backup file is automatically removed after commit.
        'remove_after_commit' => false,
    ],
];

$result = $stream->transaction(function($stream) {
    // ...not shown...
}, 1, null, $options);

When the above show example is executed, a backup file will be created within a "my_file_backups" directory. The backup file's extension will be set to *.bak and the filename will include a datetime.

/my_file_backups
    orders.txt_2022_04_03_182045_225174.bak

Unless the remove_after_commit setting is set to true, then the backup file will not be purged after a successful transaction commit.

Customisation

As previously mentioned, if using stream transactions in a Laravel application, then you can add or change profiles in the config/streams.php configuration file. When you wish to use a specific transaction, state the profile name in the $profile argument of the transaction() method.

$stream = FileStream::open('orders.txt', 'r+b');

$result = $stream->transaction(function($stream) {
    // ...not shown...
}, 3, 'my-stream-transaction-profile');

However, when using this package outside Laravel, then you have similar options to customise the behaviour, as for the locking mechanism. You are encouraged to extend the FileStream component and overwrite the getDefaultTransactionFactory() method.

use Aedart\Streams\FileStream;
use Aedart\Contracts\Streams\BufferSizes;
use Aedart\Contracts\Streams\Locks\LockTypes;
use Aedart\Contracts\Streams\Transactions\Factory;
use Aedart\Streams\Transactions\TransactionFactory;
use Aedart\Streams\Transactions\Drivers\CopyWriteReplaceDriver;

class MyFileStream extends FileStream
{
    public function getDefaultTransactionFactory(): Factory|null
    {
        $profiles = [
            'my-transaction-profile' => [
                'driver' => CopyWriteReplaceDriver::class,
                'options' => [
                    'maxMemory' => 10 * BufferSizes::BUFFER_1MB,

                    'lock' => [
                        'enabled' => true,
                        'profile' => 'default',
                        'type' => LockTypes::EXCLUSIVE,
                        'timeout' => 0.01,
                    ],

                    'backup' => [
                        'enabled' => true,
                        'directory' => getcwd() . DIRECTORY_SEPARATOR . 'backup',
                        'remove_after_commit' => false,
                    ],
                ]
            ]
        ];

        $default = 'my-transaction-profile';
        
        return new TransactionFactory($profiles, $default);
    }
}

For additional information about each of the above shown settings, please review the config/streams.php located inside this package.

Onward

The transaction mechanism can be useful, when you need to perform unsafe or risky stream content manipulation. You SHOULD enable backup of files, if you plan to use this feature in a production environment. Additionally, if the default provided stream transaction driver is not to your liking, then you can implement your own version. Please review the source code of \Aedart\Streams\Transactions\Drivers\CopyWriteReplaceDriver for more information.

Edit page
Last Updated: 16/02/2023, 09:10
Contributors: Alin Eugen Deac, alin
Prev
Locking
Next
Meta