You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axkit-dev@xml.apache.org by ma...@sergeant.org on 2006/08/23 00:22:38 UTC

[SVN] [110] Initial AIO support

Revision: 110
Author:   matt
Date:     2006-08-22 22:22:18 +0000 (Tue, 22 Aug 2006)

Log Message:
-----------
Initial AIO support
Made gallery a bit faster on resizes

Modified Paths:
--------------
    trunk/NOTICE
    trunk/lib/AxKit2.pm
    trunk/plugins/demo/gallery

Added Paths:
-----------
    trunk/plugins/aio/
    trunk/plugins/aio/uri_to_file

Modified: trunk/NOTICE
===================================================================
--- trunk/NOTICE	2006-08-22 22:21:28 UTC (rev 109)
+++ trunk/NOTICE	2006-08-22 22:22:18 UTC (rev 110)
@@ -1,2 +1,5 @@
-This product includes software developed by
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
+Apache AxKit (Version 2)
+Copyright 2006 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).

Modified: trunk/lib/AxKit2.pm
===================================================================
--- trunk/lib/AxKit2.pm	2006-08-22 22:21:28 UTC (rev 109)
+++ trunk/lib/AxKit2.pm	2006-08-22 22:22:18 UTC (rev 110)
@@ -21,7 +21,10 @@
 use AxKit2::Server;
 use AxKit2::Config;
 use AxKit2::Console;
+use AxKit2::Constants qw(LOGINFO);
 
+use constant AIO_AVAILABLE => eval { require IO::AIO };
+
 our $VERSION = '1.0';
 
 sub run {
@@ -40,6 +43,12 @@
         AxKit2::Server->create($server);
     }
     
+    if (AIO_AVAILABLE) {
+        AxKit2::Client->log(LOGINFO, "Adding AIO support");
+        Danga::Socket->AddOtherFds (IO::AIO::poll_fileno() =>
+                                    \&IO::AIO::poll_cb);
+    }
+
     # print $_, "\n" for sort keys %INC;
     
     Danga::Socket->EventLoop();

Added: trunk/plugins/aio/uri_to_file
===================================================================
--- trunk/plugins/aio/uri_to_file	2006-08-22 22:21:28 UTC (rev 109)
+++ trunk/plugins/aio/uri_to_file	2006-08-22 22:22:18 UTC (rev 110)
@@ -0,0 +1,156 @@
+#!/usr/bin/perl -w
+
+# Copyright 2001-2006 The Apache Software Foundation
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+=head1 NAME
+
+uri_to_file - Convert URIs to filenames, and  other critical stuff
+
+=head1 SYNOPSIS
+
+  Plugin uri_to_file
+  
+  # optionally:
+  DirectoryIndex index.html
+
+=head1 DESCRIPTION
+
+This plugin provides the filename for a given URI. It is absolutely required
+that you load this plugin if you wish to serve files off the filesystem, or else
+re-implement its functionality somehow.
+
+It also splits off the path_info off the URI, provides a redirect when a
+directory without a "/" is requested, and implements C<DirectoryIndex> (see below).
+
+=head1 CONFIG
+
+=head2 DirectoryIndex STRING
+
+A filename to append to directory requests. If the file exists then it will be
+the filename used instead of the directory itself.
+
+=cut
+
+use File::Spec::Functions qw(canonpath catfile);
+use AxKit2::Utils qw(uri_decode);
+
+sub register {
+    my $self = shift;
+    $self->register_hook('uri_translation' => 'hook_uri_translation1');
+    $self->register_hook('uri_translation' => 'hook_uri_translation2');
+}
+
+sub init {
+    my $self = shift;
+    $self->register_config('DirectoryIndex', sub { $self->set_dirindex(@_) });
+}
+
+sub set_dirindex {
+    my ($self, $config, $value) = @_;
+    my $key = $self->plugin_name . '::dirindex';
+    $config->notes($key, $value);
+}
+
+sub hook_uri_translation1 {
+    my ($self, $hd, $uri) = @_;
+    
+    $self->log(LOGINFO, "translate: $uri");
+    
+    
+    $uri =~ s/(\?.*)//;
+    my $removed = $1 || '';
+    
+    my $original_uri = $uri;
+    
+    $uri = uri_decode($uri);
+    
+    my $root = $self->config->path;
+    
+    $uri =~ s/^\Q$root// || die "$uri did not match config path $root";
+    
+    my $path = canonpath(catfile($self->config->docroot, $uri));
+    $path .= '/' if $uri =~ /\/$/; # canonpath will strip a trailing slash
+    
+    my $path_info = '';
+    
+    # set default return value
+    $self->client->notes('uri_to_file_retcode', DECLINED);
+    
+    # the default will work in most cases, so we do this once here.
+    $hd->filename($path);
+    
+    # save these so they get locked in for the closure.
+    my $client = $self->client;
+    my $config = $self->config;
+    
+    IO::AIO::aio_stat($path, sub {
+        $self->log(LOGINFO, "aio_stat($path) returned ($_[0])");
+        if ($_[0]) {
+            # error (usually file didn't exist).
+            print "error\n";
+            while ($path =~ /\// && !-f $path) {
+                $path =~ s/(\/[^\/]*)$//;
+                $path_info = $1 . $path_info;
+            }
+            if ($path_info && -f _) {
+                $hd->path_info($path_info);
+                substr($original_uri, 0 - length($path_info)) = '';
+                $hd->request_uri($original_uri);
+            }
+            else {
+                $path .= $path_info;
+                $hd->path_info('');
+            }
+        }
+        elsif (-d _) {
+            print "dir\n";
+            # URI didn't end in a slash - need to redirect
+            if ($original_uri !~ /\/$/) {
+                $self->log(LOGINFO, "redirecting to $original_uri/$removed");
+                $client->headers_out->header('Location', "$original_uri/$removed");
+                $client->notes('uri_to_file_retcode', REDIRECT);
+                return;
+            }
+            if (my $dirindex = $config->notes($self->plugin_name . '::dirindex')) {
+                my $filepath = catfile($path, $dirindex);
+                $path = $filepath if -f $filepath;
+            }
+        }
+        elsif (-f _) {
+            print "file\n";
+            return;
+        }
+        else {
+            # neither a dir nor a file
+            die "Unknown entity type: $path";
+        }
+        
+        print "Setting filename to $path\n";
+        $hd->filename($path);
+        
+        $client->finish_continuation;
+    });
+    
+    return CONTINUATION;
+}
+
+# This allows us to return REDIRECT above
+sub hook_uri_translation2 {
+    my $self = shift;
+    
+    print "Continuation returns!\n";
+    return $self->client->notes('uri_to_file_retcode');
+}

Modified: trunk/plugins/demo/gallery
===================================================================
--- trunk/plugins/demo/gallery	2006-08-22 22:21:28 UTC (rev 109)
+++ trunk/plugins/demo/gallery	2006-08-22 22:22:18 UTC (rev 110)
@@ -57,8 +57,6 @@
 use RDF::Core::Model::Serializer;
 use AxKit2::Utils qw(uri_decode uri_encode);
 
-use constant EPEG_AVAILABLE => eval { require Image::Epeg };
-
 our $DEFAULT_SIZE = '133 640 800 1024';
 
 sub hook_xmlresponse {
@@ -136,18 +134,7 @@
     
     my $out;
     
-    if ($type eq 'jpeg' && EPEG_AVAILABLE) {
-        my $epg = Image::Epeg->new($file);
-        $epg->resize($size, $size, Image::Epeg::MAINTAIN_ASPECT_RATIO());
-        $out = $epg->get_data();
-        if (!$out) {
-            # Epeg didn't work. Resort to Imager anyway
-            $self->resize_image($size, $file, $type, \$out);
-        }
-    }
-    else {
-        $self->resize_image($size, $file, $type, \$out);
-    }
+    $self->resize_image($size, $file, $type, \$out);
     
     $cache->set("$file+$size", $out);
     
@@ -175,22 +162,36 @@
     $quality = 'normal' if $quality ne 'preview';
     $quality = 'normal' if $self->client->param('size') ne 'thumb';
     
-    $self->log(LOGINFO, "Scaling to $size");
+    $self->log(LOGINFO, "Scaling to $size with quality: $quality");
     
+    my $doublesize = $size < (($w > $h ? $w : $h)/2);
+    
+    if ($quality eq 'normal' && $doublesize) {
+        $self->log(LOGINFO, "Doing an initial shrinkage in preview mode");
+        my $thumb = $image->scale(qtype => "preview",
+                                  $w > $h ? (xpixels => $w/2)
+                                          : (ypixels => $h/2)
+                                 );
+        
+        $image = $thumb;
+    }
+    
     my $thumb = $image->scale(qtype => $quality, 
                                $w > $h ?
                                    (xpixels => $size)
                                  : (ypixels => $size)
                              );
     
-    $self->log(LOGINFO, "sharpening $thumb");
+    if ($doublesize) {
+        $self->log(LOGINFO, "sharpening $thumb");
+        
+        # Sharpen a bit with a convolve filter
+        $thumb->filter(
+            type=>'conv',
+            coef => [-0.2, 1, -0.2]
+            ) if $quality eq 'normal';
+    }
     
-    # Sharpen a bit with a convolve filter
-    $thumb->filter(
-        type=>'conv',
-        coef => [-0.2, 1, -0.2]
-        ) if $quality eq 'normal';
-    
     $thumb->write(data => $out, type => $type)
         or die "Cannot write to scalar: ", $thumb->errstr;
 }