mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-02-25 16:05:19 +00:00
00_KNXIO.pm: fix IO-write queing (high loaad) (Forum #127792)
git-svn-id: https://svn.fhem.de/fhem/trunk@28304 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
6e2dd35571
commit
9493ad1498
@ -1,5 +1,6 @@
|
|||||||
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide.
|
||||||
# Do not insert empty lines here, update check depends on it.
|
# Do not insert empty lines here, update check depends on it.
|
||||||
|
- bugfix: 00_KNXIO: fix problem IO-write queing (high load), Forum #127792
|
||||||
- feature: Update to new version, see Forum #127701
|
- feature: Update to new version, see Forum #127701
|
||||||
- feature: 20_X10: added SetExtensions, see Forum #136278
|
- feature: 20_X10: added SetExtensions, see Forum #136278
|
||||||
- bugfix: 98_CDCOpenData: Fehlerbehandlung SFTP
|
- bugfix: 98_CDCOpenData: Fehlerbehandlung SFTP
|
||||||
|
@ -63,10 +63,15 @@
|
|||||||
# 02/10/2023 Rate limit for write (set/get-cmd) from KNX-Modul
|
# 02/10/2023 Rate limit for write (set/get-cmd) from KNX-Modul
|
||||||
# remove unused imports...
|
# remove unused imports...
|
||||||
# add $readingFnAttributes to AttrList
|
# add $readingFnAttributes to AttrList
|
||||||
# xx/11/2023 performance tuning KNXIO_write
|
# 25/11/2023 performance tuning KNXIO_write
|
||||||
# replace GP_export function
|
# replace GP_export function
|
||||||
# PBP cleanup -1
|
# PBP cleanup -1
|
||||||
# change regex's (unnecessary i)
|
# change regex's (unnecessary i)
|
||||||
|
# xx/12/2023 modify KNXIO_Ready fn
|
||||||
|
# fix problem in _write2
|
||||||
|
# add recovery on open Timeout - mode H
|
||||||
|
# modify dipatch2/ processFIFO
|
||||||
|
# new Attr KNXIOdebug - special debugging on Loglvl 1
|
||||||
|
|
||||||
|
|
||||||
package KNXIO; ## no critic 'package'
|
package KNXIO; ## no critic 'package'
|
||||||
@ -143,7 +148,7 @@ sub Initialize {
|
|||||||
$hash->{UndefFn} = \&KNXIO_Undef;
|
$hash->{UndefFn} = \&KNXIO_Undef;
|
||||||
$hash->{ShutdownFn} = \&KNXIO_Shutdown;
|
$hash->{ShutdownFn} = \&KNXIO_Shutdown;
|
||||||
|
|
||||||
$hash->{AttrList} = 'disable:1 verbose:1,2,3,4,5 enableKNXscan:0,1,2 ' . $readingFnAttributes;
|
$hash->{AttrList} = 'disable:1 verbose:1,2,3,4,5 enableKNXscan:0,1,2 KNXIOdebug:1,2,3,4,5 ' . $readingFnAttributes;
|
||||||
$hash->{Clients} = 'KNX';
|
$hash->{Clients} = 'KNX';
|
||||||
$hash->{MatchList} = { '1:KNX' => '^C.*' };
|
$hash->{MatchList} = { '1:KNX' => '^C.*' };
|
||||||
|
|
||||||
@ -224,8 +229,9 @@ sub KNXIO_Define {
|
|||||||
$hash->{PARTIAL} = q{};
|
$hash->{PARTIAL} = q{};
|
||||||
# define helpers
|
# define helpers
|
||||||
$hash->{KNXIOhelper}->{FIFO} = []; # read fifo array
|
$hash->{KNXIOhelper}->{FIFO} = []; # read fifo array
|
||||||
$hash->{KNXIOhelper}->{FIFOTIMER} = 0;
|
$hash->{KNXIOhelper}->{FIFOW} = []; # write fifo array
|
||||||
$hash->{KNXIOhelper}->{FIFOMSG} = q{};
|
# $hash->{KNXIOhelper}->{FIFOTIMER} = 0;
|
||||||
|
# $hash->{KNXIOhelper}->{FIFOMSG} = q{};
|
||||||
|
|
||||||
# Devio-parameters
|
# Devio-parameters
|
||||||
$hash->{nextOpenDelay} = $reconnectTO;
|
$hash->{nextOpenDelay} = $reconnectTO;
|
||||||
@ -513,8 +519,12 @@ sub KNXIO_Ready {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
return if (! $init_done || exists($hash->{DNSWAIT}) || IsDisabled($name) == 1);
|
return if (! $init_done || exists($hash->{DNSWAIT}) || IsDisabled($name) == 1);
|
||||||
return if (exists($hash->{NEXT_OPEN}) && $hash->{NEXT_OPEN} > gettimeofday()); # avoid open loop
|
return if (ReadingsVal($name, 'state', q{}) eq 'connected' );
|
||||||
return KNXIO_openDev($hash) if (ReadingsVal($name, 'state', 'disconnected') ne 'connected');
|
if (exists($hash->{NEXT_OPEN}) ) { # avoid open loop
|
||||||
|
InternalTimer($hash->{NEXT_OPEN},\&KNXIO_openDev,$hash);
|
||||||
|
} else {
|
||||||
|
KNXIO_openDev($hash);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,7 +604,7 @@ sub KNXIO_Write {
|
|||||||
}
|
}
|
||||||
|
|
||||||
## rate limit
|
## rate limit
|
||||||
push(@{$hash->{KNXIOhelper}->{FIFOW}},$mode,$completemsg);
|
push(@{$hash->{KNXIOhelper}->{FIFOW}},qq{$mode $completemsg});
|
||||||
return KNXIO_Write2($hash);
|
return KNXIO_Write2($hash);
|
||||||
}
|
}
|
||||||
KNXIO_Log ($name, 2, qq{Could not send message $msg});
|
KNXIO_Log ($name, 2, qq{Could not send message $msg});
|
||||||
@ -605,17 +615,22 @@ sub KNXIO_Write {
|
|||||||
sub KNXIO_Write2 {
|
sub KNXIO_Write2 {
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
|
|
||||||
|
my $name = $hash->{NAME};
|
||||||
my $timenow = gettimeofday();
|
my $timenow = gettimeofday();
|
||||||
my $lastwrite = $hash->{KNXIOhelper}->{lastWrite} // $timenow;
|
my $nextwrite = $hash->{KNXIOhelper}->{nextWrite} // $timenow;
|
||||||
my $adddelay = (scalar(@{$hash->{KNXIOhelper}->{FIFOW}}) - 2) * 0.1;
|
my $count = scalar(@{$hash->{KNXIOhelper}->{FIFOW}});
|
||||||
if ($lastwrite > $timenow) {
|
RemoveInternalTimer($hash, \&KNXIO_Write2);
|
||||||
KNXIO_Log ($hash->{NAME}, 3, q{frequent IO-write cmd - delayed});
|
return if($count == 0);
|
||||||
InternalTimer($lastwrite + $adddelay, \&KNXIO_Write2,$hash);
|
|
||||||
|
if ($nextwrite > $timenow) {
|
||||||
|
my $adddelay = $count * 0.07;
|
||||||
|
KNXIO_Log ($name, 4, qq{frequent IO-write - Nr.msg= $count});
|
||||||
|
KNXIO_Log ($name, 1, qq{DEBUG1>>frequent IO-write - Nr.msg= $count}) if (AttrVal($name,'KNXIOdebug',0) == 1);
|
||||||
|
InternalTimer($nextwrite + $adddelay, \&KNXIO_Write2,$hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$hash->{KNXIOhelper}->{lastWrite} = $timenow + 0.2; # add delay
|
$hash->{KNXIOhelper}->{nextWrite} = $timenow + 0.07; # add delay
|
||||||
my $mode = shift(@{$hash->{KNXIOhelper}->{FIFOW}});
|
my ($mode,$completemsg) = split(/\s/xms,shift(@{$hash->{KNXIOhelper}->{FIFOW}}),2);
|
||||||
my $completemsg = shift(@{$hash->{KNXIOhelper}->{FIFOW}});
|
|
||||||
|
|
||||||
my $ret = 0;
|
my $ret = 0;
|
||||||
if ($mode eq 'M') {
|
if ($mode eq 'M') {
|
||||||
@ -629,7 +644,11 @@ sub KNXIO_Write2 {
|
|||||||
InternalTimer($timenow + 1.5, \&KNXIO_TunnelRequestTO, $hash);
|
InternalTimer($timenow + 1.5, \&KNXIO_TunnelRequestTO, $hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KNXIO_Log ($hash->{NAME}, 4, qq{Mode= $mode buf=} . unpack('H*',$completemsg) . qq{ rc= $ret});
|
|
||||||
|
$count--;
|
||||||
|
InternalTimer($timenow + 0.07, \&KNXIO_Write2,$hash) if ($count > 0);
|
||||||
|
KNXIO_Log ($name, 5, qq{Mode= $mode buf=} . unpack('H*',$completemsg) . qq{ rc= $ret});
|
||||||
|
KNXIO_Log ($name, 1, qq{DEBUG1>>IO-write processed- Nr.msg remain= $count}) if (AttrVal($name,'KNXIOdebug',0) == 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -788,9 +807,8 @@ sub KNXIO_openDev {
|
|||||||
$conn = IO::Socket::INET->new(PeerAddr => "$host:$port", Type => SOCK_DGRAM, Proto => 'udp', Reuse => 1);
|
$conn = IO::Socket::INET->new(PeerAddr => "$host:$port", Type => SOCK_DGRAM, Proto => 'udp', Reuse => 1);
|
||||||
if (!($conn)) {
|
if (!($conn)) {
|
||||||
KNXIO_Log ($name, 2, qq{can't connect: $ERRNO}) if(!$reopen);
|
KNXIO_Log ($name, 2, qq{can't connect: $ERRNO}) if(!$reopen);
|
||||||
$readyfnlist{"$name.$param"} = $hash;
|
KNXIO_disconnect($hash);
|
||||||
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
readingsSingleUpdate($hash, 'state', 'disconnected', 1);
|
||||||
$hash->{NEXT_OPEN} = gettimeofday() + $reconnectTO;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete $hash->{NEXT_OPEN};
|
delete $hash->{NEXT_OPEN};
|
||||||
@ -801,6 +819,7 @@ sub KNXIO_openDev {
|
|||||||
delete $readyfnlist{"$name.$param"};
|
delete $readyfnlist{"$name.$param"};
|
||||||
$selectlist{"$name.$param"} = $hash;
|
$selectlist{"$name.$param"} = $hash;
|
||||||
|
|
||||||
|
readingsSingleUpdate($hash, 'state', 'opened', 1);
|
||||||
KNXIO_Log ($name, 3, ($reopen)?'reappeared':'opened');
|
KNXIO_Log ($name, 3, ($reopen)?'reappeared':'opened');
|
||||||
$ret = KNXIO_init($hash);
|
$ret = KNXIO_init($hash);
|
||||||
}
|
}
|
||||||
@ -844,6 +863,9 @@ sub KNXIO_init {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
my $mode = $hash->{model};
|
my $mode = $hash->{model};
|
||||||
|
|
||||||
|
$hash->{KNXIOhelper}->{FIFO} = []; # read fifo array
|
||||||
|
$hash->{KNXIOhelper}->{FIFOW} = []; # write fifo array
|
||||||
|
|
||||||
if ($mode =~ m/[ST]/xms) {
|
if ($mode =~ m/[ST]/xms) {
|
||||||
my $opengrpcon = pack('nnnC',(5,0x26,0,0)); # KNX_OPEN_GROUPCON
|
my $opengrpcon = pack('nnnC',(5,0x26,0,0)); # KNX_OPEN_GROUPCON
|
||||||
::DevIo_SimpleWrite($hash,$opengrpcon,0);
|
::DevIo_SimpleWrite($hash,$opengrpcon,0);
|
||||||
@ -852,6 +874,7 @@ sub KNXIO_init {
|
|||||||
elsif ($mode eq 'H') {
|
elsif ($mode eq 'H') {
|
||||||
my $connreq = KNXIO_prepareConnRequ($hash);
|
my $connreq = KNXIO_prepareConnRequ($hash);
|
||||||
::DevIo_SimpleWrite($hash,$connreq,0);
|
::DevIo_SimpleWrite($hash,$connreq,0);
|
||||||
|
InternalTimer(gettimeofday() + 2, \&KNXIO_openTO, $hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
# state 'connected' is set in decode_EMI (model ST) or in readH (model H)
|
# state 'connected' is set in decode_EMI (model ST) or in readH (model H)
|
||||||
@ -869,6 +892,8 @@ sub KNXIO_handleConn {
|
|||||||
|
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
|
RemoveInternalTimer($hash, \&KNXIO_openTO) if ($hash->{model} eq q{H});
|
||||||
|
|
||||||
if (exists($hash->{KNXIOhelper}->{startdone})) {
|
if (exists($hash->{KNXIOhelper}->{startdone})) {
|
||||||
KNXIO_Log ($name, 3, q{connected});
|
KNXIO_Log ($name, 3, q{connected});
|
||||||
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
readingsSingleUpdate($hash, 'state', 'connected', 1);
|
||||||
@ -940,19 +965,21 @@ sub KNXIO_dispatch {
|
|||||||
|
|
||||||
### called from FIFO TIMER
|
### called from FIFO TIMER
|
||||||
sub KNXIO_dispatch2 {
|
sub KNXIO_dispatch2 {
|
||||||
# my ($hash, $outbuf ) = ($_[0]->{h}, $_[0]->{m});
|
## my ($hash, $outbuf ) = ($_[0]->{h}, $_[0]->{m});
|
||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
|
my $buf = shift;
|
||||||
|
|
||||||
my $buf = $hash->{KNXIOhelper}->{FIFOMSG};
|
# my $buf = $hash->{KNXIOhelper}->{FIFOMSG};
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
$hash->{KNXIOhelper}->{FIFOTIMER} = 0;
|
# $hash->{KNXIOhelper}->{FIFOTIMER} = 0;
|
||||||
|
|
||||||
$hash->{'msg_count'}++;
|
$hash->{'msg_count'}++;
|
||||||
$hash->{'msg_time'} = TimeNow();
|
$hash->{'msg_time'} = TimeNow();
|
||||||
|
|
||||||
Dispatch($hash, $buf);
|
Dispatch($hash, $buf);
|
||||||
|
|
||||||
RemoveInternalTimer($hash,'KNXIO::KNXIO_dispatch2');
|
# $hash->{KNXIOhelper}->{FIFOTIMER} = 0;
|
||||||
|
# RemoveInternalTimer($hash,\&KNXIO_dispatch2);
|
||||||
KNXIO_processFIFO($hash);
|
KNXIO_processFIFO($hash);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -962,13 +989,14 @@ sub KNXIO_processFIFO {
|
|||||||
my $hash = shift;
|
my $hash = shift;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
|
|
||||||
RemoveInternalTimer($hash,'KNXIO::KNXIO_processFIFO');
|
RemoveInternalTimer($hash,\&KNXIO_processFIFO);
|
||||||
|
|
||||||
if ($hash->{KNXIOhelper}->{FIFOTIMER} != 0) { # dispatch still running, do a wait loop
|
# if ($hash->{KNXIOhelper}->{FIFOTIMER} != 0) { # dispatch still running, do a wait loop
|
||||||
KNXIO_Log ($name, 5, q{dispatch not complete, waiting});
|
# KNXIO_Log ($name, 5, q{dispatch not complete, waiting});
|
||||||
InternalTimer(gettimeofday() + 0.1, 'KNXIO::KNXIO_processFIFO', $hash);
|
# InternalTimer(gettimeofday() + 0.1, \&KNXIO_processFIFO, $hash);
|
||||||
return;
|
# $hash->{KNXIOhelper}->{FIFOTIMER} = 0;
|
||||||
}
|
# return;
|
||||||
|
# }
|
||||||
|
|
||||||
my @que = @{$hash->{KNXIOhelper}->{FIFO}};
|
my @que = @{$hash->{KNXIOhelper}->{FIFO}};
|
||||||
my $queentries = scalar(@que);
|
my $queentries = scalar(@que);
|
||||||
@ -981,11 +1009,18 @@ sub KNXIO_processFIFO {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($queentries > 0) { # process timer is not running & fifo not empty
|
if ($queentries > 0) { # process timer is not running & fifo not empty
|
||||||
$hash->{KNXIOhelper}->{FIFOMSG} = shift (@que);
|
# $hash->{KNXIOhelper}->{FIFOMSG} = shift (@que);
|
||||||
|
my $msg = shift (@que);
|
||||||
@{$hash->{KNXIOhelper}->{FIFO}} = @que;
|
@{$hash->{KNXIOhelper}->{FIFO}} = @que;
|
||||||
$hash->{KNXIOhelper}->{FIFOTIMER} = 1;
|
# $hash->{KNXIOhelper}->{FIFOTIMER} = 1;
|
||||||
KNXIO_Log ($name, 4, qq{buf=$hash->{KNXIOhelper}->{FIFOMSG} Nr_msgs=$queentries});
|
# KNXIO_Log ($name, 4, qq{buf=$hash->{KNXIOhelper}->{FIFOMSG} Nr_msgs=$queentries});
|
||||||
InternalTimer(gettimeofday() + 0.05, 'KNXIO::KNXIO_dispatch2', $hash); # allow time for duplicate msgs to be read
|
# InternalTimer(gettimeofday() + 0.05, \&KNXIO_dispatch2, $hash); # allow time for duplicate msgs to be read
|
||||||
|
KNXIO_Log ($name, 4, qq{dispatching buf=$msg Nr_msgs=$queentries});
|
||||||
|
KNXIO_dispatch2($hash, $msg);
|
||||||
|
if ($queentries > 1) {
|
||||||
|
InternalTimer(gettimeofday() + 0.05, \&KNXIO_processFIFO, $hash); # allow time for new/duplicate msgs to be read
|
||||||
|
# $hash->{KNXIOhelper}->{FIFOTIMER} = 1;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
KNXIO_Log ($name, 5, q{finished});
|
KNXIO_Log ($name, 5, q{finished});
|
||||||
@ -1203,7 +1238,7 @@ sub KNXIO_keepAlive {
|
|||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
$hash->{KNXIOhelper}->{CNTRTO} = $cntrTO;
|
$hash->{KNXIOhelper}->{CNTRTO} = $cntrTO;
|
||||||
|
|
||||||
KNXIO_Log ($name, 4, 'send conn state request - expect connection state response');
|
KNXIO_Log ($name, 5, q{send conn state request - expect connection state response});
|
||||||
|
|
||||||
my $msg = pack('nnnCCnnnn',(0x0610,0x0207,16,$hash->{KNXIOhelper}->{CCID},0, 0x0801,0,0,0));
|
my $msg = pack('nnnCCnnnn',(0x0610,0x0207,16,$hash->{KNXIOhelper}->{CCID},0, 0x0801,0,0,0));
|
||||||
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
RemoveInternalTimer($hash,\&KNXIO_keepAlive);
|
||||||
@ -1252,6 +1287,16 @@ sub KNXIO_TunnelRequestTO {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
### handle opentimeout for mode H
|
||||||
|
sub KNXIO_openTO {
|
||||||
|
my $hash = shift;
|
||||||
|
|
||||||
|
KNXIO_Log ($hash, 3, q{open timeout occured, attempt retry});
|
||||||
|
KNXIO_closeDev($hash);
|
||||||
|
InternalTimer(gettimeofday() + $reconnectTO,\&KNXIO_openDev,$hash);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
### unified Log handling
|
### unified Log handling
|
||||||
### calling param: same as Log3: hash/name/undef, loglevel, logtext
|
### calling param: same as Log3: hash/name/undef, loglevel, logtext
|
||||||
### prependes device, subroutine, linenr. to Log msg
|
### prependes device, subroutine, linenr. to Log msg
|
||||||
|
Loading…
x
Reference in New Issue
Block a user