Apache-Wyrd

 view release on metacpan or  search on metacpan

Wyrd/Services/Index.pm  view on Meta::CPAN


=item (void) C<delete_index> (void)

Zero all data in the index and open a new one.

=cut

sub delete_index {
	my ($self) = @_;
	$self->write_db;
	$self->db->truncate(my $count);
	$self->db_big->truncate(my $bcount) if ($self->bigfile);
	if ($self->bigfile) {
		$self->db_big->truncate(my $bcount);
	}
	$self->close_db;
	return;
}

sub newstatus {
	my ($self, $status) = @_;
	return undef if ($self->status eq 'X');#Once it's bad, it stays there.
	$self->{'status'} = $status;
	return;
}

sub check_error {
	my ($self) = @_;
	if ($self->transactions) {
		if ($self->error) {
			warn "transactions are enabled and errors occurred:";
			carp (join("\n", $self->error));
		}
	} elsif ($self->strict) {
		if ($self->error) {
			croak (join("\n", $self->error));
		}
	} else {
		if ($self->error) {
			$self->{'status'} = 'X';
		}
		return undef if ($self->quiet);
		carp (join("\n", $self->error));
	}
	return;
}

sub read_db {
	my ($self) = @_;
	if ($self->status eq 'R') {
		return $self->db;
	} elsif ($self->status eq 'RW') {
		$self->close_db;
	}
	my %index = ();
	my $index = tie %index, 'BerkeleyDB::Btree', -Filename => $self->file, -Flags => DB_RDONLY, -Env => $self->env, -Mode => 0660;
	$self->set_error ("Can't open the index for reading.") unless ($index);
	$self->check_error;
	$self->{'db'} = $index;
	if ($self->bigfile) {
		my %bindex = ();
		my $bindex = tie %bindex, 'BerkeleyDB::Btree', -Filename => $self->bigfilename, -Flags => DB_RDONLY, -Env => $self->env, -Mode => 0660;
		$self->set_error("Can't open the wholetext index for reading.") unless ($bindex);
		$self->check_error;
		$self->{'db_big'} = $bindex;
	}
	$self->newstatus('R');
	return $index;
}

sub write_db {
	my ($self) = @_;
	if ($self->status eq 'RW') {
		return $self->db;
 	} elsif ($self->status eq 'R') {
		$self->close_db;
	}
	my %index = ();
	my $index = tie (%index, 'BerkeleyDB::Btree', -Filename => $self->file, -Flags => DB_CREATE, -Env => $self->env, -Mode => 0660);
	$self->set_error ("Can't open/create the index for writing.") unless ($index);
	$self->check_error;
	$self->{'db'} = $index;
	if ($self->bigfile) {
		my %bindex = ();
		my $bindex = tie %bindex, 'BerkeleyDB::Btree', -Filename => $self->bigfilename, -Flags => DB_CREATE, -Env => $self->env, -Mode => 0660;
		$self->{'db_big'} = $bindex;
		$self->set_error("Can't open/create the wholetext index for writing.") unless ($bindex);
		$self->check_error;
	}
	my $fingerprint = int(rand(100000));
	$index->db_put("\xff%fingerprint", $fingerprint);
	$index->db_get("\xff%fingerprint", my $challenge);
	$self->set_error("open returned an unwriteable DB on write_db() -- '$challenge' should be '$fingerprint'") unless ($fingerprint == $challenge);
	$self->check_error;
	$self->newstatus('RW');
	return $index;
}

sub recover_db {
	my ($self) = @_;
	if ($self->status =~ /^RW?$/) {
		$self->close_db;
	}
	if ($self->current_transaction) {
		warn "aborting current transaction..." unless ($self->quiet);
		my $result = $self->current_transaction->txn_abort;
		warn $result if ($result);
		$self->{'current_transaction'} = undef;
	}
	my $error = 0;
	if ($self->allow_recovery) {
		warn 'attempting recovery using DB_RECOVER environment flag';
		my $env = BerkeleyDB::Env->new(
			-Home			=> $self->directory,
			-Flags			=> DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER | DB_CREATE,
			-ErrFile		=> *STDERR,
			-Verbose		=> 1,
		);
		my %index = ();
		my $errors = '';
		my $index = tie (%index, 'BerkeleyDB::Btree', -Filename => $self->file, -Flags => DB_CREATE, -Env => $env, -Mode => 0660);
		$error = 1 unless ($index);
		$errors .= $env->status . "\n" if ($error and $env);
		$index->db_close if ($index);
		$index = undef;
		%index = ();
		if ($self->bigfile) {
			my %bindex = ();
			my $bindex = tie %bindex, 'BerkeleyDB::Btree', -Filename => $self->bigfilename, -Flags => DB_CREATE, -Env => $env, -Mode => 0660;
			$self->{'db_big'} = $bindex;
			$error = 1 unless ($bindex);
			$errors .= $env->status . "\n" if ($error and $env);
			$bindex->db_close if ($bindex);
			$bindex = undef;
			%bindex = ();
		}
		if ($error) {
			warn 'attempting recovery using DB_RECOVER_FATAL environment flag';
			$error = 0;
			my $env = BerkeleyDB::Env->new(
				-Home			=> $self->directory,
				-Flags			=> DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER_FATAL | DB_CREATE,
				-ErrFile		=> *STDERR,
				-Verbose		=> 1,
			);
			die "could not init fatal recovery environment" unless ($env);
			my $index = tie (%index, 'BerkeleyDB::Btree', -Filename => $self->file, -Flags => DB_CREATE, -Env => $env, -Mode => 0660);
			$error = 1 unless($index);
			$errors .= $env->status . "\n" if ($error);
			$index->db_close if ($index);
			$index = undef;
			%index = ();
			if ($self->bigfile) {
				my %bindex = ();
				my $bindex = tie %bindex, 'BerkeleyDB::Btree', -Filename => $self->bigfilename, -Flags => DB_CREATE, -Env => $env, -Mode => 0660;
				$self->{'db_big'} = $bindex;
				$error = 1 unless ($bindex);
				$errors .= $env->status . "\n" if ($error);
				$bindex->db_close if ($bindex);
				$bindex = undef;
				%bindex = ();
			}
			die ("recovery of database failed for both DB_RECOVER and DB_RECOVER_FATAL: $errors") if ($error);
			$self->check_error;
		}
	}
}

sub close_db {
	my ($self) = @_;
	my $index = $self->{'db'};
	if (ref($index) and UNIVERSAL::isa($index, 'Apache::Wyrd::Services::Index')) {
		$index->db_close;
		untie %{$self->{'db'}};
		$self->{'db'} = undef;
		delete ($self->{'status'}); #close the DB ref
		$self->{'status'} = undef;
	}
	$index = $self->{'db_big'};
	if (ref($index) and UNIVERSAL::isa($index, 'Apache::Wyrd::Services::Index')) {
		$index->db_close;
		untie %{$self->{'db_big'}};
		$self->{'db_big'} = undef;
		delete ($self->{'status'}); #close the DB ref
		$self->{'status'} = undef;
	}
	my $env = $self->{'env'};
	if (ref($env) and UNIVERSAL::isa($env, 'BerkeleyDB::Env')) {
		$self->{'env'} = undef;
	}
	undef $index;
	undef $env;
	return;
}

=pod

=item (scalar) C<update_entry> (Apache::Wyrd::Interfaces::Indexable ref)

Called by an indexable object, passing itself as the argument, in order to
update it's entry in the index.  This method calls C<index_foo> for every
attribute B<foo> in the index, storing that value under the attribute entry for
that object.  The function always returns a message about the process.

update_entry will always check index_timestamp and index_digest.  If the stored
value and the returned value agree on either attribute, the index will not be
updated.  This behavior can be overridden by returning a true value from method
C<force_update>.

Index will also check for an C<index_runtime_flags> method and call it to
determine if the indexed object is attempting to modify the behavior of the
update during the process of updating for debugging purposes.  Currently, it
recognizes the following flags:

=over

=item debug/nodebug

Turn on debugging messages for the course of this update, even if debug is
not specified in the arguments to C<new>.



( run in 0.781 second using v1.01-cache-2.11-cpan-2398b32b56e )