diff --git a/fhem/CHANGED b/fhem/CHANGED index aaab6fad2..9b6e30e6e 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,8 @@ # 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. + - feature: 93_DbRep: V7.5.4, dumpFilesKeep can be set to "0", new attribute + "ftpDumpFilesKeep" for version management on FTP, + delSeqDoublets optimized for consumption of resources - feature: 98_DOIFtools: blockinginfo added to running timer info - change: 73_PRESENCE: following attributes were renamed: * ping_count => pingCount diff --git a/fhem/FHEM/93_DbRep.pm b/fhem/FHEM/93_DbRep.pm index 30287e655..38dae7f6f 100644 --- a/fhem/FHEM/93_DbRep.pm +++ b/fhem/FHEM/93_DbRep.pm @@ -36,6 +36,11 @@ # ########################################################################################################################### # Versions History: +# +# 7.5.4 24.01.2018 delseqdoubl_DoParse reviewed to optimize memory usage, executeBeforeDump executeAfterDump +# now available for "delSeqDoublets" +# 7.5.3 23.01.2018 new attribute "ftpDumpFilesKeep", version management added to FTP-usage +# 7.5.2 23.01.2018 fix typo DumpRowsCurrrent, dumpFilesKeep can be set to "0", commandref revised # 7.5.1 20.01.2018 DumpDone changed to create background_processing_time before execute "executeAfterProc" # Commandref updated # 7.5.0 16.01.2018 DbRep_OutputWriteToDB, set options display/writeToDB for (max|min|sum|average|diff)Value @@ -288,7 +293,7 @@ use Encode qw(encode_utf8); sub DbRep_Main($$;$); sub DbLog_cutCol($$$$$$$); # DbLog-Funktion nutzen um Daten auf maximale Länge beschneiden -my $DbRepVersion = "7.5.1"; +my $DbRepVersion = "7.5.4"; my %dbrep_col = ("DEVICE" => 64, "TYPE" => 64, @@ -320,21 +325,22 @@ sub DbRep_Initialize($) { "dumpDirRemote ". "dumpMemlimit ". "dumpSpeed ". - "dumpFilesKeep:1,2,3,4,5,6,7,8,9,10 ". + "dumpFilesKeep:0,1,2,3,4,5,6,7,8,9,10 ". "executeBeforeProc ". "executeAfterProc ". "expimpfile ". "fetchRoute:ascent,descent ". - "ftpUse:1,0 ". - "ftpUser ". - "ftpUseSSL:1,0 ". "ftpDebug:1,0 ". "ftpDir ". + "ftpDumpFilesKeep:1,2,3,4,5,6,7,8,9,10 ". "ftpPassive:1,0 ". "ftpPwd ". "ftpPort ". "ftpServer ". "ftpTimeout ". + "ftpUse:1,0 ". + "ftpUser ". + "ftpUseSSL:1,0 ". "aggregation:hour,day,week,month,no ". "diffAccept ". "limit ". @@ -515,6 +521,16 @@ sub DbRep_Set($@) { return undef; } + if ($opt =~ m/delSeqDoublets/ && $hash->{ROLE} ne "Agent") { + $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; + if ($prop =~ /delete/ && !AttrVal($hash->{NAME}, "allowDeletion", 0)) { + return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; + } + DbRep_beforeproc($hash, "delSeq"); + DbRep_Main($hash,$opt,$prop); + return undef; + } + if ($hash->{HELPER}{RUNNING_BACKUP_CLIENT}) { $setlist = "Unknown argument $opt, choose one of ". (($hash->{ROLE} ne "Agent")?"cancelDump:noArg ":""); @@ -529,7 +545,7 @@ sub DbRep_Set($@) { } ####################################################################################################### - ## keine Aktionen außer Backup/Restore solange Reopen xxxx im DbLog-Device läuft + ## keine Aktionen außer die über diesem Eintrag solange Reopen xxxx im DbLog-Device läuft ####################################################################################################### if ($hash->{dbloghash}{HELPER}{REOPEN_RUNS} && $opt !~ /\?/) { my $ro = (split(" ",FmtDateTime(gettimeofday()+$hash->{dbloghash}{HELPER}{REOPEN_RUNS})))[1]; @@ -544,13 +560,6 @@ sub DbRep_Set($@) { my $table = $prop?$prop:"history"; DbRep_Main($hash,$opt,$table); - } elsif ($opt =~ m/delSeqDoublets/ && $hash->{ROLE} ne "Agent") { - $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; - if ($prop =~ /delete/ && !AttrVal($hash->{NAME}, "allowDeletion", 0)) { - return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; - } - DbRep_Main($hash,$opt,$prop); - } elsif ($opt =~ /fetchrows/ && $hash->{ROLE} ne "Agent") { $hash->{LASTCMD} = $prop?"$opt $prop":"$opt"; my $table = $prop?$prop:"history"; @@ -4154,15 +4163,16 @@ sub delseqdoubl_DoParse($) { $selspec = "DEVICE,READING,TIMESTAMP,VALUE"; # SQL zusammenstellen für DB-Abfrage - $sql = createSelectSql($hash,$table,$selspec,$device,$reading,"?","?","ORDER BY TIMESTAMP ASC"); + $sql = createSelectSql($hash,$table,$selspec,$device,$reading,"?","?","ORDER BY DEVICE,READING,TIMESTAMP ASC"); $sth = $dbh->prepare_cached($sql); # DB-Abfrage zeilenweise für jeden Timearray-Eintrag - my @row_array; my @remain; my @todel; - my $ndel = 0; - my $rt = 0; + my $nremain = 0; + my $ntodel = 0; + my $ndel = 0; + my $rt = 0; no warnings 'uninitialized'; @@ -4177,7 +4187,7 @@ sub delseqdoubl_DoParse($) { $st = [gettimeofday]; # SQL zusammenstellen für Logausgabe - my $sql1 = createSelectSql($hash,"history",$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",''); + my $sql1 = createSelectSql($hash,$table,$selspec,$device,$reading,"'$runtime_string_first'","'$runtime_string_next'",''); Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); eval{$sth->execute($runtime_string_first, $runtime_string_next);}; @@ -4191,89 +4201,80 @@ sub delseqdoubl_DoParse($) { # SQL-Laufzeit ermitteln $rt = $rt+tv_interval($st); - - @row_array = map { $_->[0]."_ESC_".$_->[1]."_ESC_".($_->[2] =~ s/ /_ESC_/r)."_ESC_".$_->[3]."\n" } @{$sth->fetchall_arrayref()}; - - $nrows = $#row_array+1; # Anzahl der Ergebniselemente - # s/ /_ESC_/ for @row_array; # Leerzeichen in TIMESTAMP escapen - + # Beginn Löschlogik, Zusammenstellen der löschenden DS (warping) # Die Arrays @remain, @sel enthalten die VERBLEIBENDEN Datensätze - my $i = 0; my (@sel,@warp); my ($or,$oor,$odev,$oread,$oval,$ooval,$ndev,$nread,$nval); - my @sort = sort @row_array; # Reihenfolge device,reading sortieren - foreach my $nr (@sort) { - if($i == 0 || $i == $#sort) { - push (@sel,$nr); - } else { - ($ndev,$nread,undef,undef,$nval) = split("_ESC_", $nr); # Werte des aktuellen Elements - $or = pop @sel; # das letzte Element der Liste - ($odev,$oread,undef,undef,$oval) = split("_ESC_", $or); # Value des letzten Elements - if (looks_like_number($oval) && $var) { # Varianz +- falls $val numerischer Wert - $var1 = $oval + $var; - $var2 = $oval - $var; - } else { - undef $var1; - undef $var2; - } - $oor = pop @sel; # das vorletzte Element der Liste - $ooval = (split '_ESC_', $oor)[-1]; # Value des vorletzten Elements - if ($ndev.$nread ne $odev.$oread) { - push (@sel,$oor); - push (@sel,$or); - push (@sel,$nr); - } elsif ($ooval eq $oval || (($var1 && ($ooval <= $var1)) && ($var2 && ($var2 <= $ooval))) ) { - push (@sel,$oor); - push (@sel,$nr); - # Log3 ($name, 5, "DbRep $name -> warping: $or"); - push (@warp,$or); # Array der zu löschenden Datensätze - if ($opt =~ /delete/ && $or) { # delete Datensätze - my ($dev,$read,$date,$time,$val) = split("_ESC_", $or); - my $dt = $date." ".$time; - chomp($val); - $dev =~ s/'/''/g; # escape ' with '' - $read =~ s/'/''/g; # escape ' with '' - $val =~ s/'/''/g; # escape ' with '' - $st = [gettimeofday]; - my $dsql = "delete FROM $table where TIMESTAMP = '$dt' AND DEVICE = '$dev' AND READING = '$read' AND VALUE = '$val';"; - my $sthd = $dbh->prepare($dsql); - Log3 ($name, 4, "DbRep $name - SQL execute: $dsql"); + foreach my $nr (map { $_->[0]."_ESC_".$_->[1]."_ESC_".($_->[2] =~ s/ /_ESC_/r)."_ESC_".$_->[3] } @{$sth->fetchall_arrayref()}) { + ($ndev,$nread,undef,undef,$nval) = split("_ESC_", $nr); # Werte des aktuellen Elements + $or = pop @sel; # das letzte Element der Liste + ($odev,$oread,undef,undef,$oval) = split("_ESC_", $or); # Value des letzten Elements + if (looks_like_number($oval) && $var) { # Varianz +- falls $val numerischer Wert + $var1 = $oval + $var; + $var2 = $oval - $var; + } else { + undef $var1; + undef $var2; + } + $oor = pop @sel; # das vorletzte Element der Liste + $ooval = (split '_ESC_', $oor)[-1]; # Value des vorletzten Elements + if ($ndev.$nread ne $odev.$oread) { + push (@sel,$oor); + push (@sel,$or); + push (@sel,$nr); + } elsif (($ooval eq $oval && $oval eq $nval) || ($var1 && $var2 && ($ooval <= $var1) && ($var2 <= $ooval) && ($nval <= $var1) && ($var2 <= $nval)) ) { + push (@sel,$oor); + push (@sel,$nr); + push (@warp,$or); # Array der zu löschenden Datensätze + if ($opt =~ /delete/ && $or) { # delete Datensätze + my ($dev,$read,$date,$time,$val) = split("_ESC_", $or); + my $dt = $date." ".$time; + chomp($val); + $dev =~ s/'/''/g; # escape ' with '' + $read =~ s/'/''/g; # escape ' with '' + $val =~ s/'/''/g; # escape ' with '' + $st = [gettimeofday]; + my $dsql = "delete FROM $table where TIMESTAMP = '$dt' AND DEVICE = '$dev' AND READING = '$read' AND VALUE = '$val';"; + my $sthd = $dbh->prepare($dsql); + Log3 ($name, 4, "DbRep $name - SQL execute: $dsql"); - eval {$sthd->execute();}; - if ($@) { - $err = encode_base64($@,""); - Log3 ($name, 2, "DbRep $name - $@"); - $dbh->disconnect; - Log3 ($name, 4, "DbRep $name -> BlockingCall delseqdoubl_DoParse finished"); - return "$name|''|''|$err|''|$opt"; - } - $ndel = $ndel+$sthd->rows; - $dbh->commit() if(!$dbh->{AutoCommit}); + eval {$sthd->execute();}; + if ($@) { + $err = encode_base64($@,""); + Log3 ($name, 2, "DbRep $name - $@"); + $dbh->disconnect; + Log3 ($name, 4, "DbRep $name -> BlockingCall delseqdoubl_DoParse finished"); + return "$name|''|''|$err|''|$opt"; + } + $ndel = $ndel+$sthd->rows; + $dbh->commit() if(!$dbh->{AutoCommit}); - $rt = $rt+tv_interval($st); - } - } else { - push (@sel,$oor); - push (@sel,$or); - push (@sel,$nr); - } - } - $i++; - } - - push(@remain,@sel) if(@sel); # die verbleibenden Datensätze nach Ausführung - push(@todel,@warp) if(@warp); # die zu löschenden Datensätze - # Ende Löschlogik + $rt = $rt+tv_interval($st); + } + } else { + push (@sel,$oor); + push (@sel,$or); + push (@sel,$nr); + } + } + if(@sel && $opt =~ /adviceRemain/) { + # die verbleibenden Datensätze nach Ausführung (nur zur Anzeige) + push(@remain,@sel) if($#remain+1 < $limit); + } + if(@warp && $opt =~ /adviceDelete/) { + # die zu löschenden Datensätze (nur zur Anzeige) + push(@todel,@warp) if($#todel+1 < $limit); + } + $nremain = $nremain + $#sel if(@sel); + $ntodel = $ntodel + $#warp if(@warp); } - - my $nremain = $#remain+1; - my $ntodel = $#todel+1; + my $retn = ($opt =~ /adviceRemain/)?$nremain:($opt =~ /adviceDelete/)?$ntodel:$ndel; my @retarray = ($opt =~ /adviceRemain/)?@remain:($opt =~ /adviceDelete/)?@todel:" "; - splice(@retarray,$limit+10); + # splice(@retarray,$limit+10); if ($utf8 && @retarray) { $rowlist = Encode::encode_utf8(join('|', @retarray)); } elsif(@retarray) { @@ -4319,6 +4320,7 @@ sub delseqdoubl_ParseDone($) { my @row; my $l = 1; my $reading_runtime_string; + my $erread; Log3 ($name, 4, "DbRep $name -> Start BlockingCall delseqdoubl_ParseDone"); @@ -4330,6 +4332,9 @@ sub delseqdoubl_ParseDone($) { return; } + # Befehl nach Procedure ausführen + $erread = DbRep_afterproc($hash, "delSeq"); + # Readingaufbereitung readingsBeginUpdate($hash); @@ -4355,6 +4360,7 @@ sub delseqdoubl_ParseDone($) { $l++; } } + use warnings; my $sfx = AttrVal("global", "language", "EN"); $sfx = ($sfx eq "EN" ? "" : "_$sfx"); @@ -5536,7 +5542,7 @@ sub mysql_DoDumpClientSide($) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } # SQL-Startzeit @@ -5551,7 +5557,7 @@ sub mysql_DoDumpClientSide($) { Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } my @mysql_version = $sth->fetchrow; @@ -5605,7 +5611,7 @@ sub mysql_DoDumpClientSide($) { Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } while ( $value = $sth->fetchrow_hashref()) { @@ -5670,7 +5676,7 @@ sub mysql_DoDumpClientSide($) { $err = encode_base64($@,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } if($optimize_tables_beforedump) { @@ -5679,7 +5685,7 @@ sub mysql_DoDumpClientSide($) { ($err,$db_MB_start,$db_MB_end) = mysql_optimize_tables($hash,$dbh,@tablenames); if ($err) { $err = encode_base64($err,""); - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } } @@ -5708,7 +5714,7 @@ sub mysql_DoDumpClientSide($) { $err = encode_base64($@,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } $db_tables{$tablename}{Rows} = $sth->fetchrow; $sth->finish; @@ -5750,7 +5756,7 @@ sub mysql_DoDumpClientSide($) { Log3 ($name, 2, "DbRep $name - $err"); $err = encode_base64($err,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } else { Log3 ($name, 5, "DbRep $name - New dumpfile $sql_file has been created."); } @@ -5786,7 +5792,7 @@ sub mysql_DoDumpClientSide($) { $err = encode_base64($@,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } @ergebnis = $sth->fetchrow; @@ -5823,7 +5829,7 @@ sub mysql_DoDumpClientSide($) { $err = encode_base64($@,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } while (@ar = $sth->fetchrow) { @@ -5859,7 +5865,7 @@ sub mysql_DoDumpClientSide($) { $err = encode_base64($@,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } while ( @ar = $sth->fetchrow) { @@ -5913,9 +5919,11 @@ sub mysql_DoDumpClientSide($) { # SQL-Laufzeit ermitteln my $rt = tv_interval($st); - # Dumpfile per FTP senden - my ($ftperr,$ftpmsg) = sendftp($hash,$sql_file); + # Dumpfile per FTP senden und versionieren + my ($ftperr,$ftpmsg,@ftpfd) = sendftp($hash,$backupfile); my $ftp = $ftperr?encode_base64($ftperr,""):$ftpmsg?encode_base64($ftpmsg,""):0; + my $ffd = join(", ", @ftpfd); + $ffd = $ffd?encode_base64($ffd,""):0; # alte Dumpfiles löschen my @fd = deldumpfiles($hash,$backupfile); @@ -5933,7 +5941,7 @@ sub mysql_DoDumpClientSide($) { Log3 ($name, 3, "DbRep $name - Finished backup of database $dbname, total time used: ".sprintf("%.0f",$brt)." sec."); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpClientSide finished"); -return "$name|$rt|''|$sql_file|$drc|$drh|$fsize|$ftp|$bfd"; +return "$name|$rt|''|$sql_file|$drc|$drh|$fsize|$ftp|$bfd|$ffd"; } #################################################################################################### @@ -5968,7 +5976,7 @@ sub mysql_DoDumpServerSide($) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpServerSide finished"); - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } # Eigenschaften der vorhandenen Tabellen ermitteln (SHOW TABLE STATUS -> Rows sind nicht exakt !!) @@ -5987,7 +5995,7 @@ sub mysql_DoDumpServerSide($) { Log3 ($name, 2, "DbRep $name - Error executing: '".$query."' ! MySQL-Error: ".$@); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpServerSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } while ( $value = $sth->fetchrow_hashref()) { @@ -6016,7 +6024,7 @@ sub mysql_DoDumpServerSide($) { $err = encode_base64($@,""); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpServerSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } if($optimize_tables_beforedump) { @@ -6025,7 +6033,7 @@ sub mysql_DoDumpServerSide($) { ($err,$db_MB_start,$db_MB_end) = mysql_optimize_tables($hash,$dbh,@tablenames); if ($err) { $err = encode_base64($err,""); - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } } @@ -6056,7 +6064,7 @@ sub mysql_DoDumpServerSide($) { Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpServerSide finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } $sth->finish; @@ -6074,9 +6082,11 @@ sub mysql_DoDumpServerSide($) { Log3 ($name, 3, "DbRep $name - Number of exported datasets: $drh"); Log3 ($name, 3, "DbRep $name - Size of backupfile: ".byte_output($filesize)); - # Dumpfile per FTP senden - my ($ftperr,$ftpmsg) = sendftp($hash,$bfile); + # Dumpfile per FTP senden und versionieren + my ($ftperr,$ftpmsg,@ftpfd) = sendftp($hash,$bfile); my $ftp = $ftperr?encode_base64($ftperr,""):$ftpmsg?encode_base64($ftpmsg,""):0; + my $ffd = join(", ", @ftpfd); + $ffd = $ffd?encode_base64($ffd,""):0; # alte Dumpfiles löschen my @fd = deldumpfiles($hash,$bfile); @@ -6094,7 +6104,7 @@ sub mysql_DoDumpServerSide($) { Log3 ($name, 3, "DbRep $name - Finished backup of database $dbname - total time used: ".sprintf("%.0f",$brt)." seconds"); Log3 ($name, 4, "DbRep $name -> BlockingCall mysql_DoDumpServerSide finished"); -return "$name|$rt|''|$dump_path_rem$bfile|n.a.|$drh|$fsize|$ftp|$bfd"; +return "$name|$rt|''|$dump_path_rem$bfile|n.a.|$drh|$fsize|$ftp|$bfd|$ffd"; } #################################################################################################### @@ -6128,7 +6138,7 @@ sub sqlite_DoDump($) { $err = encode_base64($@,""); Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 4, "DbRep $name -> BlockingCall sqlite_DoDump finished"); - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } if($optimize_tables_beforedump) { @@ -6149,7 +6159,7 @@ sub sqlite_DoDump($) { Log3 ($name, 4, "DbRep $name -> BlockingCall sqlite_DoDump finished"); $sth->finish; $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } # Endgröße ermitteln @@ -6181,7 +6191,7 @@ sub sqlite_DoDump($) { Log3 ($name, 2, "DbRep $name - $@"); Log3 ($name, 4, "DbRep $name -> BlockingCall sqlite_DoDump finished"); $dbh->disconnect; - return "$name|''|$err|''|''|''|''|''|''"; + return "$name|''|$err|''|''|''|''|''|''|''"; } $dbh->disconnect; @@ -6196,9 +6206,11 @@ sub sqlite_DoDump($) { my $fsize = byte_output($filesize); Log3 ($name, 3, "DbRep $name - Size of backupfile: ".$fsize); - # Dumpfile per FTP senden - my ($ftperr,$ftpmsg) = sendftp($hash,$bfile); + # Dumpfile per FTP senden und versionieren + my ($ftperr,$ftpmsg,@ftpfd) = sendftp($hash,$bfile); my $ftp = $ftperr?encode_base64($ftperr,""):$ftpmsg?encode_base64($ftpmsg,""):0; + my $ffd = join(", ", @ftpfd); + $ffd = $ffd?encode_base64($ffd,""):0; # alte Dumpfiles löschen my @fd = deldumpfiles($hash,$bfile); @@ -6215,7 +6227,7 @@ sub sqlite_DoDump($) { Log3 ($name, 3, "DbRep $name - Finished backup of database $dbname - total time used: ".sprintf("%.0f",$brt)." seconds"); Log3 ($name, 4, "DbRep $name -> BlockingCall sqlite_DoDump finished"); -return "$name|$rt|''|$dump_path$bfile|n.a.|n.a.|$fsize|$ftp|$bfd"; +return "$name|$rt|''|$dump_path$bfile|n.a.|n.a.|$fsize|$ftp|$bfd|$ffd"; } #################################################################################################### @@ -6234,6 +6246,7 @@ sub DumpDone($) { my $fs = $a[6]?decode_base64($a[6]):undef; my $ftp = $a[7]?decode_base64($a[7]):undef; my $bfd = $a[8]?decode_base64($a[8]):undef; + my $ffd = $a[9]?decode_base64($a[9]):undef; my $name = $hash->{NAME}; my $erread; @@ -6256,9 +6269,10 @@ sub DumpDone($) { ReadingsBulkUpdateValue($hash, "DumpFileCreated", $bfile); ReadingsBulkUpdateValue($hash, "DumpFileCreatedSize", $fs); ReadingsBulkUpdateValue($hash, "DumpFilesDeleted", $bfd); - ReadingsBulkUpdateValue($hash, "DumpRowsCurrrent", $drc); + ReadingsBulkUpdateValue($hash, "DumpRowsCurrent", $drc); ReadingsBulkUpdateValue($hash, "DumpRowsHistory", $drh); ReadingsBulkUpdateValue($hash, "FTP_Message", $ftp) if($ftp); + ReadingsBulkUpdateValue($hash, "FTP_DumpFilesDeleted", $ffd) if($ffd); ReadingsBulkUpdateValue($hash, "background_processing_time", sprintf("%.4f",$brt)); readingsEndUpdate($hash, 1); @@ -6502,10 +6516,16 @@ sub ParseAborted(@) { my ($hash,$cause) = @_; my $name = $hash->{NAME}; my $dbh = $hash->{DBH}; + my $erread; $cause = $cause?$cause:"Timeout: process terminated"; Log3 ($name, 1, "DbRep $name -> BlockingCall $hash->{HELPER}{RUNNING_PID}{fn} pid:$hash->{HELPER}{RUNNING_PID}{pid} $cause"); - + + # Befehl nach Procedure ausführen + no warnings 'uninitialized'; + $erread = DbRep_afterproc($hash, "command"); + $erread = ", ".(split("but", $erread))[1] if($erread); + $dbh->disconnect() if(defined($dbh)); ReadingsSingleUpdateValue ($hash,"state",$cause, 1); @@ -7203,6 +7223,10 @@ sub sendftp ($$) { my $ftpPwd = AttrVal($name,"ftpPwd",undef); my $ftpPassive = AttrVal($name,"ftpPassive",0); my $ftpDebug = AttrVal($name,"ftpDebug",0); + my $fdfk = AttrVal($name,"ftpDumpFilesKeep", 3); + my $pfix = (split '\.', $bfile)[-1]; + my $dbname = (split '_', $bfile)[0]; + my $ftpl = $dbname."_.*".$pfix; my ($ftperr,$ftpmsg,$ftp); # kein FTP verwenden oder möglich @@ -7286,8 +7310,23 @@ sub sendftp ($$) { $ftpmsg = "FTP: ".$file." transferred successfully to ".$ftpServer." into dir ".$ftpDir; Log3($name, 3, "DbRep $name - $ftpmsg"); } + + # Versionsverwaltung FTP-Verzeichnis + my (@ftl,@ftpfd); + if($ftpuseSSL) { + @ftl = sort grep {/^$ftpl$/} $ftp->nlst(); + } else { + @ftl = sort grep {/^$ftpl$/} @{$ftp->ls()}; + } + Log3($name, 5, "DbRep $name - FTP: filelist of \"$ftpDir\": @ftl"); + my $max = int(@ftl)-$fdfk; + for(my $i = 0; $i < $max; $i++) { + push(@ftpfd, $ftl[$i]); + Log3($name, 3, "DbRep $name - FTP: deleting old dumpfile '$ftl[$i]' "); + $ftp->delete($ftl[$i]); + } -return ($ftperr,$ftpmsg); +return ($ftperr,$ftpmsg,@ftpfd); } #################################################################################################### @@ -7685,7 +7724,7 @@ return;
| ftpUseSSL | : FTP Transfer mit SSL Verschlüsselung nach dem Dump wird eingeschaltet |
| ftpDebug | : Debugging des FTP Verkehrs zur Fehlersuche |
| ftpDir | : Verzeichnis auf dem FTP-Server in welches das File übertragen werden soll (default: "/") |
| ftpPassive | : setzen wenn passives FTP verwendet werden soll |
| ftpDumpFilesKeep | : Es wird die angegebene Anzahl Dumpfiles im <ftpDir> belassen (default: 3) |
| ftpPassive | : setzen wenn passives FTP verwendet werden soll |
| ftpPort | : FTP-Port, default: 21 |
| ftpPwd | : Passwort des FTP-Users, default nicht gesetzt |
| ftpServer | : Name oder IP-Adresse des FTP-Servers. notwendig ! |