Tim Habigt schrieb:
Hi René,

I tried your patch on the latest unstable version and it seems to work fine. I
have to admit that I didn't test it exhaustively, but I didn't notice any
problems. CPU utilization is much better on my multicore machine and there don't
seem to be errors in the rendered tiles. Thanks for your great work.


Thanks Tim ;)


and now a new version the fix follow problems

i start now all childs on start and use it and start not all childs new on a new job.. this remove the memory leake.. "hope i"


i moved all my code out in a external class lib/ThreadedRenderer.pm

i fixed an never ending wait loop in my optimizePNG

he put the job now back after a render bug

and many othe problems fixed ;)


René
diff -urbBdpN a/lib/optimizePngTasks.pm b/lib/optimizePngTasks.pm
--- a/lib/optimizePngTasks.pm	1970-01-01 01:00:00.000000000 +0100
+++ b/lib/optimizePngTasks.pm	2008-11-15 21:39:08.000000000 +0100
@@ -0,0 +1,265 @@
+package optimizePngTasks;
+
+
+use warnings;
+use strict;
+use File::Temp qw/ tempfile tempdir /;
+use File::Copy;
+use File::Path;
+use Error qw(:try);
+use TahConf;
+use tahlib;
+use threads;
+use Thread::Semaphore;
+
+
+sub new
+{
+    my $class = shift;
+    my $Config = TahConf->getConfig();
+
+    my %sharedStack :shared;
+    my @sharedFilelist :shared;
+    my @sharedTranslist :shared;
+    my $self = {
+        Config => $Config,
+        SHARED => \%sharedStack,
+        DESTROYED => 0,
+        children => [],
+        };
+
+    $self->{SHARED}->{DESTROYED} = 0;
+    $self->{SHARED}->{JOBS}  = -1;
+    $self->{SHARED}->{JOBSREADY}  = 0;
+    $self->{SHARED}->{JOBSFILES}  = [EMAIL PROTECTED];
+    $self->{SHARED}->{JOBSTRANSPARENT}  = [EMAIL PROTECTED];
+    $self->{SHARED}->{CHILDCRASH} = 0;    # TODO:
+
+    bless $self, $class;
+    return $self;
+}
+
+
+sub DESTROY
+{
+
+}
+
+########
+# kill all children threads
+########
+sub killAllChilds
+{
+    my $self = shift;
+
+    # set the destroy flag (detached childrens!)
+    $self->{'Semaphore'}->down();
+    $self->{SHARED}->{DESTROYED} = 1;
+    $self->{'Semaphore'}->up();
+
+}
+
+
+##########
+# start and init my children
+##########
+sub startChildren {
+    my $self = shift;
+    my $Config = $self->{Config};
+
+    if ($Config->get("Cores")) {
+        $self->{'maxChildren'} = $Config->get("Cores");
+        $self->{'children'} = [];
+        $self->{'Semaphore'} = Thread::Semaphore->new();
+
+        $::currentSubTask ='optimize';
+        $::progressPercent = 0;
+        ::statusMessage("init ". $self->{'maxChildren'} ." optimizePNG Child Tasks", 0, 6);
+        $self->{SHARED}->{'progress'} = 0;
+        for my $childID (1 .. $self->{'maxChildren'}) {
+            $self->{'children'}->[$childID] = threads->create(    sub  {
+
+                threads->detach();
+
+                my $sleeping = 0;
+                while (!$self->{SHARED}->{DESTROYED}) {
+
+
+                    sleep 1;
+
+                    while ($self->{SHARED}->{JOBS} < $#{$self->{SHARED}->{JOBSFILES}}) {
+                        my ($png_file, $transparent) = "";
+
+                        # access: lock()
+                        $self->{'Semaphore'}->down();
+                        $self->{SHARED}->{JOBS}++;
+                        my $pos = $self->{SHARED}->{JOBS};
+
+                        $png_file = $self->{SHARED}->{JOBSFILES}->[ $pos ];
+                        $transparent = $self->{SHARED}->{JOBSTRANSPARENT}->[ $pos ];
+                        
+                        $self->{SHARED}->{'progress'}++;
+                        if($#{$self->{SHARED}->{JOBSFILES}} >0) {
+                            $::progressPercent = 100 * $self->{SHARED}->{'progress'} / ($#{$self->{SHARED}->{JOBSFILES}}+1);
+                        }
+
+                        # access: unlock()
+                        $self->{'Semaphore'}->up();
+
+                        if( $png_file) {    # no new work? go sleeping
+                            #####
+                            # lets do my work now
+                            #####
+
+                            eval {
+                              $self->optimizePngClient($png_file, $transparent);
+                            };
+                        }
+
+                        $self->{'Semaphore'}->down();
+                        $self->{SHARED}->{JOBSREADY}++;
+                        $self->{'Semaphore'}->up();
+
+                    }
+
+
+                }
+                    ::statusMessage("optimizePNG child $childID exit" ,1,10);
+
+            }
+            ); # threads->create(sub) end
+        } # for
+
+    }
+
+} # sub startChildren
+
+# add a new job ::addJob->($png_file,$transparent)
+sub addJob {
+    my $self = shift;
+    my $png_file =  shift;
+    my $transparent = shift;
+
+    $self->{'Semaphore'}->down();
+
+    my $pos = $#{$self->{SHARED}->{JOBSFILES}}+1;
+
+    $self->{SHARED}->{JOBSFILES}->[ $pos ]  = $png_file;
+    $self->{SHARED}->{JOBSTRANSPARENT}->[ $pos ]  = $transparent;
+
+    $self->{'Semaphore'}->up();
+}
+
+
+# wait of all my jobs
+sub wait {
+    my $self = shift;
+
+    ::statusMessage("Wait of my PNG optimize Children", 0, 6);
+
+    while ($self->{SHARED}->{JOBSREADY} <= $#{$self->{SHARED}->{JOBSFILES}}) {
+        sleep 1;
+#        print $self->{SHARED}->{JOBSREADY} ." ".$#{$self->{SHARED}->{JOBSFILES}} ."\n";
+    }
+
+}
+
+# reset my lists
+sub dataReset {
+    my $self = shift;
+
+    $self->{'Semaphore'}->down();
+
+    $self->{SHARED}->{JOBS}  = -1;
+    $self->{SHARED}->{JOBSREADY}  = 0;
+    undef @{ $self->{SHARED}->{JOBSFILES} };
+    undef @{ $self->{SHARED}->{JOBSTRANSPARENT} };
+
+    $self->{SHARED}->{'progress'} = 0;
+
+    $self->{'Semaphore'}->up();
+}
+
+
+#-----------------------------------------------------------------------------
+# optimize a PNG file
+#
+# Parameters:
+#   $png_file - file name of PNG file
+#   $transparent - whether or not this is a transparent tile
+#-----------------------------------------------------------------------------
+sub optimizePngClient
+{
+    my $self = shift();
+    my $png_file = shift();
+    my $transparent = shift();
+
+    my $Config = $self->{Config};
+
+    my $optipngOptions = "-l 9";
+
+    my $redirect = ($^O eq "MSWin32") ? "" : ">/dev/null";
+    my $tmp_suffix = '.cut';
+    my $tmp_file = $png_file . $tmp_suffix;
+    my (undef, undef, $png_file_name) = File::Spec->splitpath($png_file);
+
+    my $cmd;
+    if ($transparent) {
+        # Don't quantize if it's transparent
+        rename($png_file, $tmp_file);
+    }
+    elsif (($Config->get("PngQuantizer")||'') eq "pngnq") {
+        $cmd = sprintf("\"%s\" -e .png%s -s1 -n256 %s %s",
+                       $Config->get("pngnq"),
+                       $tmp_suffix,
+                       $png_file,
+                       $redirect);
+
+        ::statusMessage("ColorQuantizing $png_file_name", 0, 6);
+        if(::runCommand($cmd, $::PID)) {
+            # Color quantizing successful
+            unlink($png_file);
+        }
+        else {
+            # Color quantizing failed
+            ::statusMessage("ColorQuantizing $png_file_name with ".$Config->get("PngQuantizer")." failed", 1, 0);
+            rename($png_file, $tmp_file);
+        }
+    }
+    else {
+        ::statusMessage("Not Color Quantizing $png_file_name, pngnq not installed?", 0, 6);
+        rename($png_file, $tmp_file);
+    }
+
+    if ($Config->get("PngOptimizer") eq "pngcrush") {
+        $cmd = sprintf("\"%s\" %s -q %s %s %s",
+                       $Config->get("Pngcrush"),
+                       $optipngOptions,
+                       $tmp_file,
+                       $png_file,
+                       $redirect);
+    }
+    elsif ($Config->get("PngOptimizer") eq "optipng") {
+           $cmd = sprintf("\"%s\" %s -out %s %s", #no quiet, because it even suppresses error output
+                          $Config->get("Optipng"),
+                          $tmp_file,
+                          $png_file,
+                          $redirect);
+    }
+    else {
+        ::statusMessage("PngOptimizer not configured (should not happen, update from svn, and check config file)", 1, 0);
+        ::talkInSleep("Install a PNG optimizer and configure it.", 15);
+    }
+
+    ::statusMessage("Optimizing $png_file_name", 0, 6);
+    if(::runCommand($cmd, $::PID)) {
+        unlink($tmp_file);
+    }
+    else {
+        ::statusMessage("Optimizing $png_file_name with " . $Config->get("PngOptimizer") . " failed", 1, 0);
+        rename($tmp_file, $png_file);
+    }
+}
+
+
+1;
diff -urbBdpN a/lib/ThreadedRenderer.pm b/lib/ThreadedRenderer.pm
--- a/lib/ThreadedRenderer.pm	1970-01-01 01:00:00.000000000 +0100
+++ b/lib/ThreadedRenderer.pm	2008-11-15 21:45:04.000000000 +0100
@@ -0,0 +1,294 @@
+package ThreadedRenderer;
+
+use warnings;
+use strict;
+use File::Temp qw/ tempfile tempdir /;
+use File::Copy;
+use File::Path;
+use Error qw(:try);
+use TahConf;
+use tahlib;
+use Tileset;
+use Request;
+
+use threads;
+use Thread::Semaphore;
+
+sub new {
+    my $class  = shift;
+    my $Config = TahConf->getConfig();
+
+    my %sharedStack : shared;
+
+    my $self = {
+        Config    => $Config,
+        SHARED    => \%sharedStack,
+        DESTROYED => 0,
+        children  => [],
+    };
+
+    my @sharedJobs : shared;
+    my @sharedJobsLayer : shared;
+    my @sharedJobsLayerDataFile : shared;
+    my @childStop : shared;
+    my @sharedJobErrors : shared;
+    my %sharedRequest : shared;
+
+    $self->{SHARED}->{RENDERERJOBS}         = [EMAIL PROTECTED];
+    $self->{SHARED}->{RENDERERJOBLAYER}     = [EMAIL PROTECTED];
+    $self->{SHARED}->{RENDERERJOBLAYERDATA} = [EMAIL PROTECTED];
+    $self->{SHARED}->{RENDERERJOBERRORS}    = [EMAIL PROTECTED];
+    $self->{SHARED}->{RENDERERJOBERROR}     = "";
+    $self->{SHARED}->{RENDERERJOBSPOS}      = -1;
+    $self->{SHARED}->{RENDERERJOBSREADY}    = 0;
+    $self->{SHARED}->{CHILDSTOP}            = [EMAIL PROTECTED];                 # for stop single clients
+    $self->{SHARED}->{JOBDIR}               = "";
+    $self->{SHARED}->{REQEST}               = \%sharedRequest;
+    $self->{SHARED}->{MAXSVGFILESIZE}       = 0;
+
+    $self->{'maxChildren'} = $Config->get("Cores");
+
+    bless $self, $class;
+    return $self;
+}
+
+sub startChildren {
+    my $self   = shift;
+    my $Config = $self->{Config};
+
+    if ( $Config->get("Cores") ) {
+
+        # add renderer childs
+        $self->{'rendererChildren'}  = [];
+        $self->{'rendererSemaphore'} = Thread::Semaphore->new();
+
+
+        ::statusMessage( "init " . $self->{'maxChildren'} . " Renderer Child Tasks", 0, 6 );
+
+        for my $childID ( 1 .. $self->{'maxChildren'} ) {
+            $self->{SHARED}->{CHILDSTOP}->[$childID] = 0;
+            $self->{'rendererChildren'}->[$childID] = threads->create(
+                sub {
+
+                    threads->detach();
+
+                    my $req    = $self->{req};
+                    my $Config = $self->{Config};
+                    my $pos;
+                    my $layer;
+                    my $layerDataFile;
+                    my $zoom;
+                    my $oldJobDir = "";
+
+                    # wait of the global destroy flag or of the singel stop flag
+                    while ( !$self->{SHARED}->{DESTROYED} ) {
+
+                        # create new tileset for a new job
+                        # TODO: bad way export some funktions to an external .pl file
+                        $self->{'rendererSemaphore'}->down();
+                        if ( $oldJobDir ne $self->{SHARED}->{JOBDIR} && $self->{SHARED}->{JOBDIR} ne "" ) {
+                            my $req = new Request;
+                            $req->ZXY(
+                                $self->{SHARED}->{REQEST}->{'z'},
+                                $self->{SHARED}->{REQEST}->{'x'},
+                                $self->{SHARED}->{REQEST}->{'y'}
+                            );
+                            $req->layers_str( $self->{SHARED}->{REQEST}->{'layers'} );
+
+                            $self->{tileset} = new Tileset( $req, 1, $self->{SHARED}->{JOBDIR} );
+                            $oldJobDir = $self->{SHARED}->{JOBDIR};
+                        }
+
+                        $self->{'rendererSemaphore'}->up();
+
+                        while ( !$self->{SHARED}->{CHILDSTOP}->[$childID]
+                            && $oldJobDir eq $self->{SHARED}->{JOBDIR}
+                            && $self->{SHARED}->{RENDERERJOBSPOS} < $#{ $self->{SHARED}->{RENDERERJOBS} } )
+                        {
+
+                            # access: lock()
+                            $self->{'rendererSemaphore'}->down();
+
+                            $self->{SHARED}->{RENDERERJOBSPOS}++;
+                            $pos           = $self->{SHARED}->{RENDERERJOBSPOS};
+                            $zoom          = $self->{SHARED}->{RENDERERJOBS}->[$pos];
+                            $layer         = $self->{SHARED}->{RENDERERJOBLAYER}->[$pos];
+                            $layerDataFile = $self->{SHARED}->{RENDERERJOBLAYERDATA}->[$pos];
+
+                            # access: unlock()
+                            $self->{'rendererSemaphore'}->up();
+
+                            ::statusMessage(
+                                "Rendererclient $childID get job $pos zoom $zoom on layer $layer $layerDataFile",
+                                1, 10 );
+
+                            ####
+                            # i do my work now
+                            ####
+                            eval {
+                                 $self->{tileset}->Render( $layer, $zoom, $layerDataFile );
+                            };
+                            if ($@) {
+                                ::statusMessage( "ERROR: Rendererclient $childID Renderer return $@", 1, 10 );
+
+                                $self->{'rendererSemaphore'}->down();
+                                $self->{SHARED}->{RENDERERJOBERROR} = 1;
+                                $self->{'rendererSemaphore'}->up();
+
+                            }
+                            $self->{'rendererSemaphore'}->down();
+                            $self->{SHARED}->{RENDERERJOBSREADY}++;
+                            $self->{'rendererSemaphore'}->up();
+                        }
+
+                        sleep 1;
+                    }
+                    ::statusMessage( "Renderer child $childID exit", 1, 10 );
+                  }    #sub;
+            );         #threads->create
+        }    # for
+    }
+}
+
+sub addJob {
+    my $self = shift;
+
+    #    my $Config = $self->{Config};
+    my $zoom          = shift;
+    my $layer         = shift;
+    my $layerDataFile = shift;
+
+    $self->{'rendererSemaphore'}->down();
+
+    my $pos = $#{ $self->{SHARED}->{RENDERERJOBS} };
+    $pos++;
+
+    $self->{SHARED}->{RENDERERJOBS}->[$pos]         = $zoom;
+    $self->{SHARED}->{RENDERERJOBLAYER}->[$pos]     = $layer;
+    $self->{SHARED}->{RENDERERJOBLAYERDATA}->[$pos] = $layerDataFile;
+
+    $self->{'rendererSemaphore'}->up();
+
+    $self->updateMaxRenderer($layerDataFile);    #TODO: move it to the svg generation after init new workflow
+}
+
+sub wait {
+    my $self = shift;
+
+    while ( $self->{SHARED}->{RENDERERJOBSREADY} <= $#{ $self->{SHARED}->{RENDERERJOBS} } ) {
+        sleep 1;
+    }
+}
+
+# reset my lists
+sub Reset {
+    my $self = shift;
+
+    $self->{'rendererSemaphore'}->down();
+
+    undef @{ $self->{SHARED}->{RENDERERJOBS} };
+    undef @{ $self->{SHARED}->{RENDERERJOBLAYER} };
+    undef @{ $self->{SHARED}->{RENDERERJOBLAYERDATA} };
+    undef @{ $self->{SHARED}->{RENDERERJOBERRORS} };
+    $self->{SHARED}->{RENDERERJOBERROR}  = "";
+
+    $self->{SHARED}->{RENDERERJOBSPOS}   = -1;
+    $self->{SHARED}->{RENDERERJOBSREADY} = 0;
+    $self->{SHARED}->{MAXSVGFILESIZE}    = 0;
+
+    # reset renderer limitation
+    for ( my $i = $self->{'maxChildren'} ; $i > 0 ; $i-- ) {
+        $self->{SHARED}->{CHILDSTOP}->[$i] = 0;
+    }
+
+    $self->{'rendererSemaphore'}->up();
+}
+
+sub setJobDir {
+    my $self   = shift;
+    my $jobDir = shift;
+
+    $self->{'rendererSemaphore'}->down();
+
+    $self->{SHARED}->{JOBDIR} = $jobDir;
+
+    $self->{'rendererSemaphore'}->up();
+
+}
+
+sub rendererError {
+    my $self   = shift;
+    if( $self->{SHARED}->{RENDERERJOBERROR} ) {
+        return($self->{SHARED}->{RENDERERJOBERROR});
+    }
+    
+    return;
+    
+}
+
+
+sub setRequest {
+    my $self = shift;
+    my $req  = shift;
+
+    my ( $z, $x, $y ) = $req->ZXY;
+    $self->{'rendererSemaphore'}->down();
+
+    $self->{SHARED}->{REQEST}->{'z'} = $z;
+    $self->{SHARED}->{REQEST}->{'x'} = $x;
+    $self->{SHARED}->{REQEST}->{'y'} = $y;
+
+    $self->{SHARED}->{REQEST}->{'layers'} = $req->layers_str();
+
+    $self->{'rendererSemaphore'}->up();
+
+}
+
+# set the maximum of paralel working renderer
+#TODO: use svg files and not the osm files for calculate
+sub updateMaxRenderer {
+    my $self     = shift;
+    my $filename = shift;
+
+    my $Config = $self->{Config};
+
+    $filename = File::Spec->join( $self->{SHARED}->{JOBDIR}, $filename );
+    my @datafileStats = stat($filename);
+
+    if ( $self->{SHARED}->{MAXSVGFILESIZE} < $datafileStats[7] ) {
+        $self->{'rendererSemaphore'}->down();
+        $self->{SHARED}->{MAXSVGFILESIZE} = $datafileStats[7];
+        $self->{'rendererSemaphore'}->up();
+    }
+    else {
+        return;
+    }
+
+    my $caMemoryUsage = $self->{SHARED}->{MAXSVGFILESIZE} / 1024 / 16;
+
+    if ( ( $caMemoryUsage * $self->{'maxChildren'} ) > $Config->get("MaxMemory") ) {
+
+        # too little memory
+        my $newMaxChildren = int( $Config->get("MaxMemory") / $caMemoryUsage );
+        $newMaxChildren = 1 if $self->{'maxChildren'} eq $newMaxChildren;
+
+        ::statusMessage(
+            "too little memory for the render job and "
+              . $self->{'maxChildren'}
+              . " Children, stopp "
+              . ( $self->{'maxChildren'} - $newMaxChildren )
+              . " renderer childs from "
+              . $self->{'maxChildren'},
+            1, 10
+        );
+
+        $self->{'rendererSemaphore'}->down();
+        for ( my $stopCount = ( $self->{'maxChildren'} - $newMaxChildren ) ; $stopCount > 0 ; $stopCount-- ) {
+            $self->{SHARED}->{CHILDSTOP}->[$stopCount] = 1;
+
+        }
+        $self->{'rendererSemaphore'}->up();
+    }
+}
+
+1;
diff -urbBdpN a/lib/Tileset.pm b/lib/Tileset.pm
--- a/lib/Tileset.pm	2008-11-15 00:07:59.530154027 +0100
+++ b/lib/Tileset.pm	2008-11-15 21:44:28.000000000 +0100
@@ -30,6 +30,12 @@ use File::Copy;
 use File::Path;
 use GD 2 qw(:DEFAULT :cmp);
 
+use threads;
+use Thread::Semaphore;
+
+use Data::Dumper;
+
+
 #-----------------------------------------------------------------------------
 # creates a new Tileset instance and returns it
 # parameter is a request object with x,y,z, and layer atributes set
@@ -41,7 +47,8 @@ sub new
     my $class = shift;
     my $Config = TahConf->getConfig();
     my $req = shift;    #Request object
-
+    my $child = shift;
+    my $jobDir = shift;
     my $self = {
         req => $req,
         Config => $Config,
@@ -53,11 +60,17 @@ sub new
 
     my $delTmpDir = 1-$Config->get('Debug');
 
+    if($child) {
+         $self->{bbox}= bbox->new(ProjectXY($req->ZXY));
+         $self->{JobDir} = $jobDir;
+    }
+    else {
     $self->{JobDir} = tempdir( 
          sprintf("%d_%d_%d_XXXXX",$self->{req}->ZXY),
          DIR      => $Config->get('WorkingDirectory'), 
 	 CLEANUP  => $delTmpDir,
          );
+    }
 
     # create true color images by default
     GD::Image->trueColor(1);
@@ -125,14 +139,11 @@ sub new
 #-----------------------------------------------------------------------------
 sub DESTROY
 {
-    my $self = shift;
-    # Don't clean up in child threads
-    return if ($self->{childThread});
+# perl call DESTROY more as on time!
 
-    # only cleanup if we are the parent thread
-    $self->cleanup();
 }
 
+
 #-----------------------------------------------------------------------------
 # generate does everything that is needed to end up with a finished tileset
 # that just needs compressing and uploading. It outputs status messages, and
@@ -149,6 +160,11 @@ sub generate
 
     $self->{bbox}= bbox->new(ProjectXY($req->ZXY));
 
+    if(defined $::GlobalChildren->{ThreadedRenderer}) {
+      $::GlobalChildren->{ThreadedRenderer}->setRequest($self->{req});
+      $::GlobalChildren->{ThreadedRenderer}->setJobDir($self->{JobDir});
+    }
+
     ::statusMessage(sprintf("Tileset (%d,%d,%d) around %.2f,%.2f", $req->ZXY, $self->{bbox}->center), 1, 0);
 
     if($req->Z >= 12)
@@ -158,9 +174,30 @@ sub generate
         #------------------------------------------------------
 
         my $beforeDownload = time();
-        my $FullDataFile = $self->downloadData($req->layers);
+
+        # TODO: FIXME: remove it on the stable version! only for debuging and tests else { its the original}
+        # add a optional testadata directory (download not the data)
+        # DO NOT UPLOAD THE RESULTS REAL!
+        my $testdatadir = File::Spec->join($Config->get("WorkingDirectory"), 'testdatadir');
+        my $testdatafile = File::Spec->join($testdatadir, 'data.osm');
+        my $FullDataFile = "";
+
+        if($Config->get("useTestDirData") && $Config->get("debug") && $Config->get("UploadToDirectory")
+             && -d $testdatadir && -f $testdatafile)
+        {
+            $FullDataFile = File::Spec->join($self->{JobDir}, 'data.osm');
+            copy($testdatafile,$FullDataFile)
+        }
+        else {
+            $FullDataFile = $self->downloadData($req->layers);
+        }
+
         ::statusMessage("Download in ".(time() - $beforeDownload)." sec",1,10); 
 
+        # manage renderer memory usage
+        # a 16mb osm file consum ca 1gb ram as svg "int(16786037/1024/16)"
+        
+
         #------------------------------------------------------
         # Handle all layers, one after the other
         #------------------------------------------------------
@@ -327,7 +364,15 @@ sub generate
     $::currentSubTask = "";
     ::keepLog($$,"GenerateTileset","stop",'x='.$req->X.',y='.$req->Y.',z='.$req->Z." for layers ".$req->layers_str);
 
+
+    # cleanup children data
+    $::GlobalChildren->{ThreadedRenderer}->Reset();
+
+
     # Cleaning up of tmpdirs etc. are called in the destructor DESTROY
+    # TODO: i move it back! DESTORY is not called only one time!
+    # the GC from perl call DESTROY a 2. time and in thread mode 2*child
+    $self->cleanup();
 }
 
 sub generateNormalLayer
@@ -356,6 +401,10 @@ sub generateNormalLayer
     {   # Forking to render zoom levels in parallel
         $self->forkedRender($layer, $layerDataFile);
     }
+    elsif ($self->{Config}->get("Cores") && defined $::GlobalChildren->{ThreadedRenderer} )
+    {    # use threads for rendering zoom levels parallel
+        $self->threadedRender($layer, $layerDataFile);
+    }
     else
     {   # Non-forking render
         $self->nonForkedRender($layer, $layerDataFile);
@@ -800,7 +849,8 @@ sub downloadData
         throw TilesetError "UTF8 test failed", "utf8";
     }
     ::resetFault("utf8"); #reset to zero if no UTF8 errors found.
-    return ($DataFile ,"");
+
+    return ($DataFile);
 }
 
 
@@ -1002,6 +1052,58 @@ sub nonForkedRender
         $self->Render($layer, $zoom, $layerDataFile)
     }
 
+    if (defined $::GlobalChildren->{optimizePngTasks}) {
+        $::GlobalChildren->{optimizePngTasks}->wait();
+        $::GlobalChildren->{optimizePngTasks}->dataReset();
+    }
+
+
+    if ($Config->get("CreateTilesetFile") and !$Config->get("LocalSlippymap")) {
+        $self->createTilesetFile($layer);
+    }
+    else {
+        $self->createZipFile($layer);
+    }
+}
+
+#-------------------------------------------------------------------
+# renders the tiles, not using threads
+# paramter: ($layer, $layerDataFile)
+#-------------------------------------------------------------------
+sub threadedRender
+{
+    my $self = shift;
+    my ($layer, $layerDataFile) = @_;
+    my $req = $self->{req};
+    my $Config = $self->{Config};
+    my $minzoom = $req->Z;
+    my $maxzoom = $Config->get($layer."_MaxZoom");
+
+
+    for (my $zoom = $maxzoom ; $zoom >= $req->Z; $zoom--) {
+
+        ::statusMessage("add renderjob zoom: $zoom " ,1,10);
+        $::GlobalChildren->{ThreadedRenderer}->addJob($zoom,$layer,$layerDataFile);
+
+    }
+
+
+    #############
+    # at this time is the client on work and the main process wait now
+    #############
+    $::GlobalChildren->{ThreadedRenderer}->wait();
+
+#    sleep 2;    # dead zone
+
+    if( $::GlobalChildren->{ThreadedRenderer}->rendererError() ) {
+        throw TilesetError "Render failure", "renderer";
+    }
+
+    if (defined $::GlobalChildren->{optimizePngTasks}) {
+        $::GlobalChildren->{optimizePngTasks}->wait();
+        $::GlobalChildren->{optimizePngTasks}->dataReset();
+    }
+
     if ($Config->get("CreateTilesetFile") and !$Config->get("LocalSlippymap")) {
         $self->createTilesetFile($layer);
     }
@@ -1286,11 +1388,16 @@ sub SplitTiles
                     print $fp $png_data;
                     close $fp;
 
+                    if(defined $::GlobalChildren->{optimizePngTasks}) {
+                        $::GlobalChildren->{optimizePngTasks}->addJob($tile_file,$Config->get("${layer}_Transparent"));
+                    }
+                    else {
                     $self->optimizePng($tile_file, $Config->get("${layer}_Transparent"));
                 }
             }
         }
     }
+    }
 }
 
 
diff -urbBdpN a/tilesGen.pl b/tilesGen.pl
--- a/tilesGen.pl	2008-11-12 18:58:51.618157433 +0100
+++ b/tilesGen.pl	2008-11-15 21:48:24.000000000 +0100
@@ -44,6 +44,9 @@ use English '-no_match_vars';
 use Encode;
 use POSIX;
 
+use optimizePngTasks;
+use ThreadedRenderer;
+
 #---------------------------------
 
 # Read the config file
@@ -74,7 +77,7 @@ else
 # set the progress indicator variables
 our $currentSubTask;
 my $progress = 0;
-our $progressJobs = 1;
+our $progressJobs :shared = 1;
 our $progressPercent = 0;
 
 my $LastTimeVersionChecked = 0;   # version is only checked when last time was more than 10 min ago
@@ -229,6 +232,27 @@ if( my $nice = $Config->get("Niceness") 
     }
 }
 
+
+#########
+# init Children for optimizePngTasks
+#########
+if ($Config->get("Cores") && !$Config->get("Fork") 
+    && ($Mode eq "xy" || $Mode eq "loop") ) {
+
+  our $GlobalChildren = {};
+
+  # start optimizePng Childs
+  $GlobalChildren->{optimizePngTasks} = optimizePngTasks->new();
+  $GlobalChildren->{optimizePngTasks}->startChildren();
+
+  #start threadedrenderer childs
+  $GlobalChildren->{ThreadedRenderer} = ThreadedRenderer->new();
+  $GlobalChildren->{ThreadedRenderer}->startChildren();
+
+}
+
+
+
 #---------------------------------
 ## Start processing
 
_______________________________________________
Tilesathome mailing list
[email protected]
http://lists.openstreetmap.org/listinfo/tilesathome

Reply via email to