Steve -- thanks -- but please credit David L. Good for the async processing
and the error handler (among other things)! I just incorporated his work.
Nice script and thanks for posting. I've taken the liberty of cross-posting
to [EMAIL PROTECTED] where that group may find this interesting, also. I
really like the use of the closure, too.
Regards,
Jeff
>
> Thanks to the excellent work of Mr. Urlwin in providing us an
> error checker
> in DBD::ODBC where we can get back all informational messages
> from commands
> (such as dbcc), I can get rid of all those old OSQL scripts for
> maintenance,
> and I can overcome another difficulty - multiple "Very Large" databases on
> servers that all must be maintained in a small maintenance window
> allowed by
> our contract. By using a Perl fork, and Mr. Urlwin's error checker, I can
> turn my maintenance jobs into an organized, multi-threaded process which
> will greatly reduce the amount of time required to perform the
> maintenance,
> and log the results, and condense the logs into our web-page (that our DBA
> staff looks at to see all the servers, and all the databases' maintenance)
> database all in one nice step.
>
> I know I am not the only DBA that has problems of large databases - small
> maintenance windows, and single threads on high-performance
> multi-processor,
> multi-raid 0+1 machines, so I thought I would post a short example here of
> how to multi-thread the maintenance, and handle the output. I am posting
> just in hope that someone will find this helpful.
>
> Note, however, that if you shouldn't do this if you use Win32, or
> any of its
> sub-components anywhere in your script (unless you know something
> I don't).
> I have never been able to make Win32 and fork play nicely
> together. Whenever
> I absolutely must use Win32, I can simulate this by arranging the code so
> that I can open multiple process pipes (I've read the documentation for
> Win32::Process which sounds like it would operate like pipes with a few
> extra nice features, but I have never used that module).
>
> Anyway, enough talk, here is the example I wanted to post for
> whomever might
> find it useful:
>
>
>
> #! perl -w
>
> use strict;
>
> # pretend like I'm going to process large databases:
>
> my @databases = qw(northwind pubs master);
>
> # I need to track what PIDS I fork.
> my @pids;
>
> # spawn a separate thread for each database to be processed:
>
> foreach (0 .. $#databases)
> {
> my $pid = fork();
>
> # using fork, the spun off pid is returned to the parent proccess.
> # therefore, if pid has a value, this is the parent process
> # if it does not, it is the child process, and we need it to get to
> work:
>
> CheckDb($databases[$_]) if ! $pid;
>
> # child processes should never arrive here. They will exit in the
> subroutine.
> # keep track of all pids for whose finish we will need to wait.
>
> push (@pids, $pid);
> }
>
> # only the parent process should arrive here.
> # child processes should exit at the end of the subroutine.
>
> # cleanup nicely before exiting:
>
> waitpid($_, 0) foreach @pids;
>
> # show a finish message:
>
> die "Complete";
>
>
> sub CheckDb
> {
> # only the child processes should arrive here.
> use DBI;
> my $dbh = DBI->connect('DBI:ODBC:northwind', 'sa', 'changed');
>
> # initialize the closure with our database name, and it will
> return the
> reference
> # to the error handler subroutine with our database name as
> part of the
> error msg.
>
> $dbh->{odbc_err_handler} = err_handler($_[0]);
> $dbh->{odbc_async_exec} = 1;
>
> # execute the checkdb on this database:
>
> my $sth = $dbh->prepare("DBCC CHECKDB('$_[0]')");
> $sth->execute();
>
>
> # failure to explicitly disconnect when running multiple threads
> sometimes
> # causes a runtime memory read/write error.
> $dbh->disconnect();
>
>
> # we do not want a child process to return. We want them to exit here.
>
> exit (0);
>
> }
>
>
> # use a closure to initialize the data such as what database is being
> processed.
> # the error_handler wants a reference to a subroutine, and a closure will
> return
> # a reference to a subroutine, initialized with the data we passed in
> calling the
> # outer subroutine.
>
> sub err_handler {
> my $db = $_[0];
> use DBI;
> my $dbh = DBI->connect('DBI:ODBC:WebSite', 'MaintJob', 'changed');
>
> # ODBC RPC to a stored procedure which will compare this message
> # with our normalmessages table, and record it in the
> logmessages table
> # if we have not already identified this pattern as a normal or "info
> only"
> # message.
>
> my $sth = $dbh->prepare(qq/{Call ProcessMessage(?, ?)}/);
> # we have our data prepared. now return a reference to an anonymous
> subroutine
> # which will actually be the error handler.
> return sub
> {
> my ($state, $msg) = @_;
> # Strip out all of the driver ID stuff
> $msg =~ s/^(\[[\w\s]*\])+//;
> # for our use here, display the message that will be logged:
> print "$db: $msg\n";
> # for to be condensed onto our website so our DBA's can review
> # when they arrive in the morning:
> $sth->execute($db, $msg);
> return 0;
> }
> }
>
>
>
> _______________________________________________
> Perl-Win32-Database mailing list
> [EMAIL PROTECTED]
> To unsubscribe: http://listserv.ActiveState.com/mailman/mysubs
>