#!/usr/bin/perl
#
# Fsdb::IO::Replayable.pm
# Copyright (C) 2007-2008 by John Heidemann <johnh@isi.edu>
# $Id: f32b4b55b6822dc8038d31e8123af0a099f77752 $
#
# This program is distributed under terms of the GNU general
# public license, version 2. See the file COPYING
# in $dblibdir for details.
#
package Fsdb::IO::Replayable;
=head1 NAME
Fsdb::IO::Replayable - support for buffering fsdb rows
=head1 SYNOPSIS
Buffer and replaying fsdb rows
=head1 FUNCTIONS
=head2 new
$replayable = new Fsdb::IO::Replayable(-writer_args => \@writer_args,
-reader_args => \@reader_args);
$writer = $replayable->writer;
$replayable->close; # warning: close replayable, NOT writer
$reader = $replayable->reader;
Creates a buffer for Fsdb::IO objects that will run with bounded memory usage.
After you close it, you can replay it one or more times by opening readers.
Arguments to the new method:
=over 4
=item -writer_args => @arref
Gives arguments to pass to Fsdb::IO::Writer to make a new stream.
=item -reader_args => @arref
Gives arguments to pass to Fsdb::IO::Reader to make a new stream.
=item -tmpdir => $dirname
Specifies wher tmpfiles go.
=back
=cut
@ISA = ();
($VERSION) = 1.0;
use Carp;
use Fsdb::Support::NamedTmpfile;
sub new {
my $class = shift @_;
my $self = bless {
_tmpdir => undef,
_reader_args => [],
_writer_args => [],
_filename => undef,
_writer => undef,
_write_version => 0, # can write if write>0
_read_version => 0, # can read if read>0 && read==write
}, $class;
my(@args) = @_;
while ($#args >= 0) {
my($key) = shift @args;
my($value) = shift @args;
if ($key eq '-writer_args') {
$self->{_writer_args} = $value;
} elsif ($key eq '-reader_args') {
$self->{_reader_args} = $value;
} elsif ($key eq '-tmpdir') {
$self->{_tmpdir} = $value;
} else {
croak "Fsdb::IO::Replayable: unknown argument $key\n";
};
};
$self->{_filename} = Fsdb::Support::NamedTmpfile::alloc($self->{_tmpdir});
return $self;
}
=head2 writer
$writer = $replayable->writer;
Return a fsdb writer object. If the file was written already,
resets it for rewriting.
=cut
sub writer {
my $self = shift @_;
$self->{_write_version}++;
$self->{_writer} = new Fsdb::IO::Writer(-file => $self->{_filename}, @{$self->{_writer_args}});
return $self->{_writer};
}
=head2 close
$replayable->close;
Close the replayable for writing.
Closes the writer object, if any.
Allows reading to start.
=cut
sub close {
my $self = shift @_;
croak "Fsdb::IO::Replayable: close called without open writer.\n"
if (!defined($self->{_writer}));
$self->{_writer}->close;
$self->{_writer} = undef;
$self->{_read_version} = $self->{_write_version};
}
=head2 reader
$reader = $replayable->reader;
Return a fsdb reader object to re-read the file.
Can be called once.
The caller is expected to close and discard any readers.
=cut
sub reader {
my $self = shift @_;
croak "Fsdb::IO::Replayable: reader called without ever having a writer.\n"
if ($self->{_read_version} == 0);
croak "Fsdb::IO::Replayable: reader called without closed writer.\n"
if ($self->{_read_version} != $self->{_write_version});
my $reader = new Fsdb::IO::Reader(-file => $self->{_filename}, @{$self->{_reader_args}});
return $reader;
}
1;