⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 execute.pm

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 PM
📖 第 1 页 / 共 2 页
字号:
    my $rv = eval {        $dbh = $self->_connect($request);        my $args = $request->dbh_method_call; # [ wantarray, 'method_name', @args ]        shift @$args; # discard wantarray        my $meth = shift @$args;        $stats->{method_calls_sth}->{$meth}++;        $sth = $dbh->$meth(@$args);        my $last = '(sth)'; # a true value (don't try to return actual sth)        # execute methods on the sth, e.g., bind_param & execute        if (my $calls = $request->sth_method_calls) {            for my $meth_call (@$calls) {                my $method = shift @$meth_call;                $stats->{method_calls_sth}->{$method}++;                $last = $sth->$method(@$meth_call);            }        }        if (my $lid_args = $request->dbh_last_insert_id_args) {            $stats->{method_calls_sth}->{last_insert_id}++;            $last_insert_id = $dbh->last_insert_id( @$lid_args );        }        $last;    };    my $response = $self->new_response_with_err($rv, $@, $dbh);    return $response if not $dbh;    $response->last_insert_id( $last_insert_id )        if defined $last_insert_id;    # even if the eval failed we still want to try to gather attribute values    # (XXX would be nice to be able to support streaming of results.    # which would reduce memory usage and latency for large results)    if ($sth) {        $response->sth_resultsets( $self->gather_sth_resultsets($sth, $request, $response) );        $sth->finish;    }    # does this request also want any dbh attributes returned?    my $dbh_attr_set;    if (my $dbh_attributes = $request->dbh_attributes) {        $dbh_attr_set = $self->gather_dbh_attributes($dbh, $dbh_attributes);    }    # XXX needs to be integrated with private_attribute_info() etc    if (my $dbh_attr = $extra_attr{$dbh->{Driver}{Name}}{dbh_after_sth}) {        @{$dbh_attr_set}{@$dbh_attr} = $dbh->FETCH_many(@$dbh_attr);    }    $response->dbh_attributes($dbh_attr_set) if $dbh_attr_set && %$dbh_attr_set;    $self->reset_dbh($dbh);    return $response;}sub gather_sth_resultsets {    my ($self, $sth, $request, $response) = @_;    my $resultsets = eval {        my $attr_names = $self->_std_response_attribute_names($sth);        my $sth_attr = {};        $sth_attr->{$_} = 1 for @$attr_names;        # let the client add/remove sth atributes        if (my $sth_result_attr = $request->sth_result_attr) {            $sth_attr->{$_} = $sth_result_attr->{$_}                for keys %$sth_result_attr;        }        my @sth_attr = grep { $sth_attr->{$_} } keys %$sth_attr;        my $row_count = 0;        my $rs_list = [];        while (1) {            my $rs = $self->fetch_result_set($sth, \@sth_attr);            push @$rs_list, $rs;            if (my $rows = $rs->{rowset}) {                $row_count += @$rows;            }            last if $self->{forced_single_resultset};            last if !($sth->more_results || $sth->{syb_more_results});         }        my $stats = $self->{stats};        $stats->{rows_returned_total} += $row_count;        $stats->{rows_returned_max} = $row_count            if $row_count > ($stats->{rows_returned_max}||0);        $rs_list;    };    $response->add_err(1, $@) if $@;    return $resultsets;}sub fetch_result_set {    my ($self, $sth, $sth_attr) = @_;    my %meta;    eval {        @meta{ @$sth_attr } = $sth->FETCH_many(@$sth_attr);        # we assume @$sth_attr contains NUM_OF_FIELDS        $meta{rowset}       = $sth->fetchall_arrayref()            if (($meta{NUM_OF_FIELDS}||0) > 0); # is SELECT        # the fetchall_arrayref may fail with a 'not executed' kind of error        # because gather_sth_resultsets/fetch_result_set are called even if        # execute() failed, or even if there was no execute() call at all.        # The corresponding error goes into the resultset err, not the top-level        # response err, so in most cases this resultset err is never noticed.    };    if ($@) {        chomp $@;        $meta{err}    = $DBI::err    || 1;        $meta{errstr} = $DBI::errstr || $@;        $meta{state}  = $DBI::state;    }    return \%meta;}sub _get_default_methods {    my ($dbh) = @_;    # returns a ref to a hash of dbh method names for methods which the driver    # hasn't overridden i.e., quote(). These don't need to be forwarded via gofer.    my $ImplementorClass = $dbh->{ImplementorClass} or die;    my %default_methods;    for my $method (@all_dbh_methods) {        my $dbi_sub = $all_dbh_methods{$method}       || 42;        my $imp_sub = $ImplementorClass->can($method) || 42;        next if $imp_sub != $dbi_sub;        #warn("default $method\n");        $default_methods{$method} = 1;    }    return \%default_methods;}sub _install_rand_callbacks {    my ($self, $dbh, $dbi_gofer_random) = @_;    my $callbacks = $dbh->{Callbacks} || {};    my $prev      = $dbh->{private_gofer_rand_fail_callbacks} || {};    # return if we've already setup this handle with callbacks for these specs    return if (($prev->{_dbi_gofer_random_spec}||'') eq $dbi_gofer_random);    $prev->{_dbi_gofer_random_spec} = $dbi_gofer_random;    my ($fail_percent, $delay_percent, $delay_duration);    my @specs = split /,/, $dbi_gofer_random;    for my $spec (@specs) {        if ($spec =~ m/^fail=(-?[.\d]+)%?$/) {            $fail_percent = $1;            next;        }        if ($spec =~ m/^delay([.\d]+)=(-?[.\d]+)%?$/) {            $delay_duration = $1;            $delay_percent  = $2;            next;        }        elsif ($spec !~ m/^(\w+|\*)$/) {            warn "Ignored DBI_GOFER_RANDOM item '$spec' which isn't a config or a dbh method name";            next;        }        my $method = $spec;        if ($callbacks->{$method} && $callbacks->{$method} != $prev->{$method}) {            warn "Callback for $method method already installed so DBI_GOFER_RANDOM callback not installed\n";            next;        }        unless (defined $fail_percent or defined $delay_percent) {            warn "Ignored DBI_GOFER_RANDOM item '$spec' because not preceeded by 'fail=N' and/or 'delayN=N'";            next;        }        warn "DBI_GOFER_RANDOM enabled for $method() - random failures/delays will be generated!\n";        $callbacks->{$method} = $self->_mk_rand_callback($method, $fail_percent, $delay_percent, $delay_duration);    }    $dbh->{Callbacks} = $callbacks;    $dbh->{private_gofer_rand_fail_callbacks} = $callbacks;}my %_mk_rand_callback_seqn;sub _mk_rand_callback {    my ($self, $method, $fail_percent, $delay_percent, $delay_duration) = @_;    my ($fail_modrate, $delay_modrate);    $fail_percent  ||= 0;  $fail_modrate  = int(1/(-$fail_percent )*100) if $fail_percent;    $delay_percent ||= 0;  $delay_modrate = int(1/(-$delay_percent)*100) if $delay_percent;    # note that $method may be "*"    return sub {        my ($h) = @_;        my $seqn = ++$_mk_rand_callback_seqn{$method};        my $delay = ($delay_percent > 0) ? rand(100) < $delay_percent :                    ($delay_percent < 0) ? !($seqn % $delay_modrate): 0;        my $fail  = ($fail_percent  > 0) ? rand(100) < $fail_percent  :                    ($fail_percent  < 0) ? !($seqn % $fail_modrate) : 0;        #no warnings 'uninitialized';        #warn "_mk_rand_callback($fail_percent:$fail_modrate, $delay_percent:$delay_modrate): seqn=$seqn fail=$fail delay=$delay";        if ($delay) {            my $msg = "DBI_GOFER_RANDOM delaying execution of $method() by $delay_duration seconds\n";            # Note what's happening in a trace message. If the delay percent is an odd            # number then use warn() so it's sent back to the client            ($delay_percent % 2 == 0) ? $h->trace_msg($msg) : warn($msg);            select undef, undef, undef, $delay_duration; # allows floating point value        }        if ($fail) {            undef $_; # tell DBI to not call the method            return $h->set_err($DBI::stderr, "fake error from $method method induced by DBI_GOFER_RANDOM env var ($fail_percent%)");        }        return;    }}sub update_stats {    my ($self, $request, $response, $frozen_request, $frozen_response, $time_received, $meta) = @_;    my $stats = $self->{stats};    $stats->{frozen_request_max_bytes} = length($frozen_request)        if length($frozen_request)  > ($stats->{frozen_request_max_bytes}||0);    $stats->{frozen_response_max_bytes} = length($frozen_response)        if length($frozen_response) > ($stats->{frozen_response_max_bytes}||0);    my $recent;    if (my $track_recent = $self->{track_recent}) {        my $recent_requests = $stats->{recent_requests} ||= [];        push @$recent_requests, $recent = {            request  => $frozen_request,            response => $frozen_response,            time_received => $time_received,            duration => dbi_time()-$time_received,	    ($meta) ? (meta => $meta) : (), # for any other info        };        shift @$recent_requests if @$recent_requests > $track_recent;    }    return $recent;}1;__END__=head1 NAMEDBI::Gofer::Execute - Executes Gofer requests and returns Gofer responses=head1 SYNOPSIS  $executor = DBI::Gofer::Execute->new( { ...config... });  $response = $executor->execute_request( $request );=head1 DESCRIPTIONAccepts a DBI::Gofer::Request object, executes the requested DBI method calls,and returns a DBI::Gofer::Response object.Any error, including any internal 'fatal' errors are caught and converted intoa DBI::Gofer::Response object.This module is usually invoked by a 'server-side' Gofer transport module.They usually have names in the "C<DBI::Gofer::Transport::*>" namespace.Examples include: L<DBI::Gofer::Transport::stream> and L<DBI::Gofer::Transport::mod_perl>.=head1 CONFIGURATION=head2 check_request_subIf defined, it must be a reference to a subroutine that will 'check' the request.It is passed the request object and the executor as its only arguments.The subroutine can either return the original request object or die with asuitable error message (which will be turned into a Gofer response).It can also construct and return a new request that should be executed insteadof the original request.=head2 check_response_subIf defined, it must be a reference to a subroutine that will 'check' the response.It is passed the response object, the executor, and the request object.The sub may alter the response object and return undef, or return a new response object.This mechanism can be used to, for example, terminate the service if specificdatabase errors are seen.=head2 forced_connect_dsnIf set, this DSN is always used instead of the one in the request.=head2 default_connect_dsnIf set, this DSN is used if C<forced_connect_dsn> is not set and the request does not contain a DSN itself.=head2 forced_connect_attributesA reference to a hash of connect() attributes. Individual attributes inC<forced_connect_attributes> will take precedence over corresponding attributesin the request.=head2 default_connect_attributesA reference to a hash of connect() attributes. Individual attributes in therequest take precedence over corresponding attributes in C<default_connect_attributes>.=head2 max_cached_dbh_per_drhIf set, the loaded drivers will be checked to ensure they don't have more thanthis number of cached connections. There is no default value. This limit is notenforced for every request.=head2 max_cached_sth_per_dbhIf set, all the cached statement handles will be cleared once the number ofcached statement handles rises above this limit. The default is 1000.=head2 forced_single_resultsetIf true, then only the first result set will be fetched and returned in the response.=head2 forced_response_attributesA reference to a data structure that can specify extra attributes to be returned in responses.  forced_response_attributes => {      DriverName => {          dbh => [ qw(dbh_attrib_name) ],          sth => [ qw(sth_attrib_name) ],      },  },This can be useful in cases where the driver has not implemented theprivate_attribute_info() method and DBI::Gofer::Execute's own fallback list ofprivate attributes doesn't include the driver or attributes you need.=head2 track_recentIf set, specifies the number of recent requests and responses that should bekept by the update_stats() method for diagnostics. See L<DBI::Gofer::Transport::mod_perl>.Note that this setting can significantly increase memory use. Use with caution.=head2 forced_gofer_randomEnable forced random failures and/or delays for testing. See L</DBI_GOFER_RANDOM> below.=head1 DRIVER-SPECIFIC ISSUESGofer needs to know about any driver-private attributes that should have theirvalues sent back to the client.If the driver doesn't support private_attribute_info() method, and very few do,then the module fallsback to using some hard-coded details, if available, forthe driver being used. Currently hard-coded details are available for themysql, Pg, Sybase, and SQLite drivers.=head1 TESTINGDBD::Gofer, DBD::Execute and related packages are well tested by executing theDBI test suite with DBI_AUTOPROXY configured to route all DBI calls via DBD::Gofer.Because Gofer includes timeout and 'retry on error' mechanisms there is a needfor some way to trigger delays and/or errors. This can be done via theC<forced_gofer_random> configuration item, or else the DBI_GOFER_RANDOM environmentvariable.=head2 DBI_GOFER_RANDOMThe value of the C<forced_gofer_random> configuration item (or else theDBI_GOFER_RANDOM environment variable) is treated as a series of tokensseparated by commas.The tokens can be one of three types:=over 4=item fail=R%Set the current failure rate to R where R is a percentage.The value R can be floating point, e.g., C<fail=0.05%>.Negative values for R have special meaning, see below.=item delayN=R%Set the current random delay rate to R where R is a percentage, and set thecurrent delay duration to N seconds. The values of R and N can be floating point,e.g., C<delay120=0.1%>.  Negative values for R have special meaning, see below.=item methodnameApplies the current current random failure rate and random delay rate and duration to the named method.If neither a fail nor delay have been set yet then a warning is generated.=backFor example:  $executor = DBI::Gofer::Execute->new( {    forced_gofer_random => "fail=0.01%,do,delay60=1%,execute",  });will cause the do() method to fail for 0.01% of calls, and the execute() method tofail 0.01% of calls and be delayed by 60 seconds on 1% of calls.If the percentage value (C<R>) is negative then instead of the failures beingtriggered randomly (via the rand() function) they are triggered via a sequencenumber. In other words "C<fail=-20%>" will mean every fifth call will fail.Each method has a distinct sequence number.=head1 AUTHORTim Bunce, L<http://www.tim.bunce.name>=head1 LICENCE AND COPYRIGHTCopyright (c) 2007, Tim Bunce, Ireland. All rights reserved.This module is free software; you can redistribute it and/ormodify it under the same terms as Perl itself. See L<perlartistic>.=cut

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -