NAME
Net::BitTorrent::Storage - Modular BitTorrent Storage Layer (v2.0.0)
SYNOPSIS
use Net::BitTorrent::Storage;
my $storage = Net::BitTorrent::Storage->new(
base_path => "./downloads",
file_tree => $metadata->{info}{'file tree'}, # From BEP 52
piece_size => 262144
);
# Write a block (16KiB) to the async cache
# $pieces_root is the SHA-256 Merkle root from the metadata
$storage->write_block($pieces_root, $offset, $data);
# Periodically flush the cache to disk
$storage->tick(0.1);
# Force all pending data to disk (e.g. before shutdown)
$storage->explicit_flush();
DESCRIPTION
Net::BitTorrent::Storage is the central I/O manager for BitTorrent swarms. It abstracts the complexity of mapping BitTorrent "pieces" and "blocks" to actual files on disk.
In a multi-file torrent, the protocol treats all files as a single contiguous stream of bytes. This class manages the translation between this "virtual file" and the physical files on the filesystem. It is particularly important for BitTorrent v2 (BEP 52) and hybrid torrents, where file alignment and padding are strictly defined.
Key Features:
BitTorrent v2 (BEP 52): Uses
pieces root(SHA-256 Merkle roots) to identify and verify files. Each file is verified independently.Merkle Trees: Maintains internal Merkle trees for each file, allowing per-block (16KiB) verification as data arrives from the network.
Hybrid Mapping: Automatically handles the padding required to align v1 pieces with v2 file boundaries. This ensures that a single v1 piece never spans multiple v2 files, which simplifies verification.
Async Disk Cache: Buffers writes in memory and flushes them in small batches during the
tick()cycle, preventing synchronous I/O from blocking the network logic.Sub-range Reads: The cache is intelligent enough to serve partial reads from larger cached blocks.
METHODS
new( %params )
Creates a new Net::BitTorrent::Storage object.
my $storage = Net::BitTorrent::Storage->new(
base_path => './downloads',
piece_size => 262144
);
This method initializes the storage engine. It sets up the base path for files and prepares the internal cache and file mapping structures.
Expected parameters:
base_path-
The root directory where all files will be stored. This is a required parameter.
file_tree- optional-
A BEP 52 file tree structure. If provided, it will be used to automatically add files to the storage.
piece_size- optional-
The size of a BitTorrent piece in bytes. Required for v1 piece mapping and hybrid torrents.
pieces_v1- optional-
A concatenated string of 20-byte SHA-1 hashes for BitTorrent v1 pieces. Used for piece verification in v1 or hybrid torrents.
add_file( $rel_path, $size, [$pieces_root] )
Adds a file to the storage manager.
my $file = $storage->add_file( 'ubuntu.iso', 2147483648, $sha256_root );
This method registers a new file within the storage manager. It returns a Net::BitTorrent::Storage::File object.
Expected parameters:
$rel_path-
The relative path to the file from the
base_path. $size-
The size of the file in bytes.
$pieces_root- optional-
The 32-byte SHA-256 Merkle root of the file (required for BEP 52).
load_file_tree( $tree )
Loads a BEP 52 file tree.
$storage->load_file_tree( $metadata->{info}{'file tree'} );
This method recursively parses a BEP 52 file tree and adds all files contained within it to the storage manager.
Expected parameters:
get_file_by_root( $root )
Retrieves a file object by its Merkle root.
my $file = $storage->get_file_by_root( $pieces_root );
This method looks up and returns the Net::BitTorrent::Storage::File object associated with the given 32-byte Merkle root. On failure, it returns undef.
Expected parameters:
set_piece_layer( $root, $layer_data )
Sets the piece layer data for a file.
$storage->set_piece_layer( $root, $hashes );
This method stores the piece layer (concatenated 32-byte SHA-256 hashes) for a specific file. These hashes are used to verify v2 pieces.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the file.
$layer_data-
The binary string containing the concatenated SHA-256 hashes for the file's piece layer.
get_hashes( $root, $base_layer, $index, $length )
Retrieves Merkle tree hashes.
my $hashes = $storage->get_hashes($root, $layer, $idx, $cnt);
This method fetches a sequence of hashes from the Merkle tree for BEP 52 HASH_REQUEST responses. On success, it returns an array reference of binary hashes. On failure, it returns undef.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the file.
$base_layer-
The tree layer to start from (0 is the leaves/blocks).
$index-
The start index in the layer.
$length-
The number of hashes to retrieve.
verify_block( $root, $index, $data )
Verifies a block against the Merkle tree (BEP 52).
my $valid = $storage->verify_block($file_root, $block_idx, $data);
This method validates a 16KiB block of data using the Merkle tree associated with the file root. It returns a boolean indicating whether the data is valid.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the file.
$index-
The block index within the file.
$data-
The 16KiB block of data to verify.
verify_block_audit( $root, $index, $data, $audit_path )
Verifies a block using an audit path.
my $valid = $storage->verify_block_audit($root, $idx, $data, $audit);
This method validates data using branch nodes (audit path), useful when the full piece layer is not yet available. It returns a boolean.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the file.
$index-
The block index within the file.
$data-
The 16KiB block of data.
$audit_path-
An array reference of hashes representing the branch nodes needed for verification.
verify_piece_v2( $root, $index, $data )
Verifies a full v2 piece.
my $valid = $storage->verify_piece_v2($root, $idx, $data);
This method validates an entire BitTorrent v2 piece against the cached piece layers. It returns a boolean.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the file.
$index-
The piece index within the file.
$data-
The full piece data.
write_block( $root, $offset, $data )
Writes data to the storage.
$storage->write_block($root, 0, $data);
This method queues a block for writing. The actual disk I/O happens asynchronously during tick().
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the target file.
$offset-
The byte offset within the file.
$data-
The data to write.
read_block( $root, $offset, $length )
Reads data from the storage.
my $data = $storage->read_block($root, 0, 16384);
This method reads data from the write cache if available, or falls back to reading from disk. It returns the data string on success or undef on failure.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the target file.
$offset-
The byte offset within the file.
$length-
The number of bytes to read.
read_global( $offset, $length )
Reads data from the virtual global file.
my $data = $storage->read_global(0, 16384);
This method treats all files in the torrent as a single contiguous stream (BEP 03). It returns the data string.
Expected parameters:
write_global( $offset, $data )
Writes data to the virtual global file.
$storage->write_global(0, $data);
This method writes data to the swarm's contiguous virtual file (BEP 03).
Expected parameters:
flush( [$count] )
Flushes pending writes to disk.
$storage->flush( 16 );
This method writes a limited number of dirty cache entries to disk. It returns the number of entries successfully flushed.
Expected parameters:
$count- optional-
The maximum number of cache entries to flush in this call. If omitted, all dirty entries are flushed.
explicit_flush( )
Forces all pending writes to disk.
$storage->explicit_flush();
This method forces all pending writes in the memory cache to be written to the physical disk immediately.
tick( [$delta] )
Performs periodic maintenance tasks.
$storage->tick( 0.1 );
This method performs periodic tasks like throttled cache flushing.
Expected parameters:
map_abs_offset( $root, $offset, $length )
Maps an offset to file segments.
my $segments = $storage->map_abs_offset( $root, $offset, $length );
This method translates an offset and length (either file-relative or global) into a list of file segments. It returns an array reference of hash references, each containing file, offset, and length.
Expected parameters:
$root-
The 32-byte SHA-256 Merkle root of the file. If
undef, the offset is treated as a global offset across all files. $offset-
The byte offset.
$length-
The length of the range in bytes.
map_v1_piece( $index )
Maps a v1 piece to file segments.
my $segments = $storage->map_v1_piece(0);
This method determines which files and offsets a BitTorrent v1 piece covers. It handles the alignment padding required for hybrid swarms (BEP 52). It returns an array reference of segments.
Expected parameters:
write_piece_v1( $index, $data )
Writes a BitTorrent v1 piece.
$storage->write_piece_v1( 0, $data );
This method writes a full v1 piece to storage, correctly mapping it across file boundaries and padding.
Expected parameters:
read_piece_v1( $index )
Reads a BitTorrent v1 piece.
my $data = $storage->read_piece_v1( 0 );
This method reads a full v1 piece from storage. It returns the piece data string.
Expected parameters:
verify_piece_v1( $index, $data )
Verifies a BitTorrent v1 piece.
my $valid = $storage->verify_piece_v1( 0, $data );
This method validates a BitTorrent v1 piece against the SHA-1 hashes provided in the constructor. It returns a boolean.
Expected parameters:
map_v2_piece( $index )
Maps a v2 piece to its file.
my ($root, $rel_idx) = $storage->map_v2_piece(0);
This method identifies which file a BitTorrent v2 piece belongs to. v2 pieces are always aligned to file boundaries. It returns the 32-byte Merkle root and the relative piece index within that file.
Expected parameters:
dump_state( )
Exports storage state.
my $state = $storage->dump_state();
This method returns the current state of the storage engine, including file statuses and internal metadata. It returns a hash reference.
load_state( $state )
Restores storage state.
$storage->load_state($state);
This method restores the storage state from a previously dumped state, allowing instant resume without re-hashing files.
Expected parameters:
base_path( )
Returns the base path for storage.
my $path = $storage->base_path();
file_tree( )
Returns the configured file tree.
my $tree = $storage->file_tree();
piece_size( )
Returns the configured piece size.
my $size = $storage->piece_size();
pieces_v1( )
Returns the configured v1 piece hashes.
my $hashes = $storage->pieces_v1();
SEE ALSO
Net::BitTorrent::Storage::File, Digest::Merkle::SHA256
AUTHOR
Sanko Robinson <sanko@cpan.org>
COPYRIGHT
Copyright (C) 2008-2026 by Sanko Robinson.
This library is free software; you can redistribute it and/or modify it under the terms of the Artistic License 2.0.