Skip to content

Commit

Permalink
Item14980: implement caching, fix performance
Browse files Browse the repository at this point in the history
  • Loading branch information
MichaelDaum committed Oct 27, 2020
1 parent cf93818 commit b45c666
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 45 deletions.
2 changes: 1 addition & 1 deletion data/System/FlexWebListExamples.txt
Expand Up @@ -150,7 +150,7 @@ needs the Foswiki:Extensions/TwistyPlugin
footer="</div>"
}%
<literal>
<style type="text/css">
<style>
.web,
.header {
margin:5px 50px;
Expand Down
7 changes: 5 additions & 2 deletions data/System/FlexWebListPlugin.txt
Expand Up @@ -116,7 +116,7 @@ The following picture illustrates when which format strings are used
<div class="format">format</div>
<div class="footer">footer</div>
</div>
<style type="text/css">
<style>
.box {
border:1px solid blue;
padding:10px;
Expand Down Expand Up @@ -146,6 +146,9 @@ See [[FlexWebListExamples]] and [[FlexWebListTree]].
---++ Change History

%TABLE{columnwidths="7em" tablewidth="100%"}%
| 27 Oct 2020: | improve performance by caching existing webs; \
monkey-patch =Foswiki::Func::getListOfWebs= with a caching one; \
ignore =NOSEARCHALL= and =SITEMAPLIST= for performance reasons |
| 28 May 2018: | extended !WebFilter to properly adhere to SITEMAPLIST and NOSEARCHALL |
| 17 Jul 2015: | more caching issues fixed |
| 26 Sep 2014: | fixed caching issue when using Foswiki:Extensions/VirtualHostingContrib (Foswiki:Main/MaikGlatki) |
Expand Down Expand Up @@ -188,7 +191,7 @@ See [[FlexWebListExamples]] and [[FlexWebListTree]].
%META:FIELD{name="Release" title="Release" value="%25$RELEASE%25"}%
%META:FIELD{name="Description" title="Description" value="%25$SHORTDESCRIPTION%25"}%
%META:FIELD{name="Repository" title="Repository" value="https://github.com/foswiki/FlexWebListPlugin"}%
%META:FIELD{name="Copyright" title="Copyright" value="2006-2018, Michael Daum http://michaeldaumconsulting.com"}%
%META:FIELD{name="Copyright" title="Copyright" value="2006-2020, Michael Daum"}%
%META:FIELD{name="License" title="License" value="GPL ([[http://www.gnu.org/copyleft/gpl.html][GNU General Public License]])"}%
%META:FIELD{name="Home" title="Home" value="Foswiki:Extensions/%25TOPIC%25"}%
%META:FIELD{name="Support" title="Support" value="Foswiki:Support/%25TOPIC%25"}%
144 changes: 134 additions & 10 deletions lib/Foswiki/Plugins/FlexWebListPlugin.pm
@@ -1,6 +1,6 @@
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
#
# Copyright (C) 2006-2018 Michael Daum http://michaeldaumconsulting.com
# Copyright (C) 2006-2020 Michael Daum http://michaeldaumconsulting.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand All @@ -17,18 +17,41 @@ package Foswiki::Plugins::FlexWebListPlugin;
use strict;
use warnings;

our $VERSION = '2.10';
our $RELEASE = '28 May 2018';
use Foswiki::Func ();
use Foswiki::Plugins ();
use Foswiki::Plugins::FlexWebListPlugin::WebFilter ();

our $VERSION = '3.20';
our $RELEASE = '27 Oct 2020';

our $NO_PREFS_IN_TOPIC = 1;
our $SHORTDESCRIPTION = 'Flexible way to display hierarchical weblists';
our %cores = ();
our $webList;

use constant TRACE => 0; # toggle me

# monkey-patch Func API
BEGIN {
no warnings 'redefine';
*Foswiki::Func::origGetListOfWebs = \&Foswiki::Func::getListOfWebs;
*Foswiki::Func::getListOfWebs =
\&Foswiki::Plugins::FlexWebListPlugin::getListOfWebs;
use warnings 'redefine';
}

sub initPlugin {

Foswiki::Func::registerTagHandler('FLEXWEBLIST', sub {
return getCore()->handler(@_);
});

my $request = Foswiki::Func::getRequestObject();
my $refresh = $request->param("refresh") || '';
if ($refresh =~ /^(on|webs|all)$/) {
clearCache();
}

return 1;
}

Expand All @@ -48,21 +71,122 @@ sub getCore() {
return $core;
}

sub finishPlugin {
foreach my $core (values %cores) {
$core->reset();
sub clearCache {

print STDERR "called clearCache\n" if TRACE;

undef $webList;
my $file = Foswiki::Func::getWorkArea("FlexWebListPlugin")."/webs.txt";
unlink $file if -e $file;
}

sub getListOfWebs {
my ($filter, $web) = @_;

print STDERR "called getListOfWebs(".($filter//'undef').",".($web//'undef').")\n" if TRACE;

unless (defined $webList) {
my $file = Foswiki::Func::getWorkArea("FlexWebListPlugin")."/webs.txt";
print STDERR "... reading from $file\n" if TRACE;
if (-e $file) {
my $data = Foswiki::Func::readFile($file);
@{$webList} = split("\n", $data) if $data;
}

unless (defined $webList) {
print STDERR "... calling store for webs\n" if TRACE;
@{$webList} = Foswiki::Func::origGetListOfWebs();
print STDERR "... saving to $file\n" if TRACE;
Foswiki::Func::saveFile($file, join("\n", sort @$webList));
}

}

if (defined $web) {
$webList = [grep {/^$web[\/\.]/} @$webList];
}

if (defined $filter) {
my $f = new Foswiki::Plugins::FlexWebListPlugin::WebFilter($filter);
my $session = $Foswiki::Plugins::SESSION;
$webList = [grep {$f->ok($session, $_)} @$webList];
}

print STDERR "... ".scalar(@$webList)." webs found\n" if TRACE;

return @$webList;
}

sub updateWeb {
my $web = shift;

return addWeb($web) if Foswiki::Func::webExists($web);
return removeWeb($web);
}

sub removeWeb {
my $web = shift;

$web = _normalizeWebName($web);
print STDERR "called removeWeb($web)\n" if TRACE;

my %knownWebs = map {_normalizeWebName($_) => 1} getListOfWebs();
if ($knownWebs{$web}) {
print STDERR "... removing web $web\n" if TRACE;
undef $knownWebs{$web};
saveWebList([keys %knownWebs]);
}
}

sub addWeb {
my $web = shift;

$web = _normalizeWebName($web);
print STDERR "called addWeb($web)\n" if TRACE;

my %knownWebs = map {_normalizeWebName($_) => 1} getListOfWebs();
unless ($knownWebs{$web}) {
print STDERR "... adding web $web\n" if TRACE;
$knownWebs{$web} = 1;
saveWebList([keys %knownWebs]);
}
}

sub saveWebList {
my ($webs) = @_;

return unless $webs;

print STDERR "saveWebList(@$webs)\n" if TRACE;
my $file = Foswiki::Func::getWorkArea("FlexWebListPlugin")."/webs.txt";
Foswiki::Func::saveFile($file, join("\n", sort @$webs));
}


sub finishPlugin {
%cores = ();
$webList = undef;
}

sub afterSaveHandler {
my ( $text, $topic, $web, $error, $meta ) = @_;

updateWeb($web);
}

sub afterRenameHandler {
my ($oldWeb, $oldTopic, $oldAttachment, $newWeb, $newTopic, $newAttachment) = @_;

return if $oldTopic;

# SMELL: does not fire on web-creation
getCore()->reset;
updateWeb($oldWeb);
updateWeb($newWeb) if $oldWeb ne $newWeb;
}

sub _normalizeWebName {
my $web = shift;

$web =~ s/\//\./g;

return $web;
}

1;
38 changes: 12 additions & 26 deletions lib/Foswiki/Plugins/FlexWebListPlugin/Core.pm
@@ -1,6 +1,6 @@
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
#
# Copyright (C) 2006-2018 Michael Daum http://michaeldaumconsulting.com
# Copyright (C) 2006-2020 Michael Daum http://michaeldaumconsulting.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand All @@ -22,7 +22,6 @@ use Foswiki::Plugins ();
use Foswiki::Plugins::FlexWebListPlugin::WebFilter ();

use constant TRACE => 0; # toggle me
use constant CACHE_WEBS => 1;

###############################################################################
# static
Expand All @@ -45,13 +44,6 @@ sub new {
return $this;
}

###############################################################################
sub reset {
my $this = shift;

undef $this->{webIterator};
}

###############################################################################
sub handler {
my ($this, $session, $params, $currentTopic, $currentWeb) = @_;
Expand Down Expand Up @@ -87,7 +79,7 @@ sub handler {
$this->{isAdmin} = '';
}

$this->{selection} =~ s/\,/ /go;
$this->{selection} =~ s/\,/ /g;
$this->{selection} = ' '.$this->{selection}.' ';

$this->{include} =~ s/\//\\\//g;
Expand All @@ -107,7 +99,7 @@ sub handler {
# compute list
my %seen;
my @list = ();
my @websList = map {s/^\s+//go; s/\s+$//go; s/\./\//go; $_} split(/\s*,\s*/, $this->{webs});
my @websList = map {my $tmp = $_; $tmp =~ s/^\s+|\s+$//g; $tmp =~ s/\./\//g; $tmp} split(/\s*,\s*/, $this->{webs});
#writeDebug("websList=".join(',', @websList));
my $allWebs = $this->getWebs();

Expand Down Expand Up @@ -297,16 +289,10 @@ sub formatWeb {

###############################################################################
sub getWebIterator {
my $this = shift;

if (defined $this->{webIterator} && CACHE_WEBS) {
$this->{webIterator}->reset;
} else {
my @webs = Foswiki::Func::getListOfWebs();
$this->{webIterator} = new Foswiki::ListIterator(\@webs);
}
my ($this, $filter) = @_;

return $this->{webIterator};
my @webs = Foswiki::Plugins::FlexWebListPlugin::getListOfWebs($filter);
return new Foswiki::ListIterator(\@webs);
}

###############################################################################
Expand All @@ -318,10 +304,10 @@ sub getWebs {
my $session = $Foswiki::Plugins::SESSION;
$filter ||= '';

#writeDebug("getWebs($filter)");
writeDebug("getWebs($filter)");

# lookup cache
my $wit = $this->getWebIterator;
my $wit = $this->getWebIterator($filter);

my @webs = ();
if ($filter) {
Expand All @@ -333,7 +319,7 @@ sub getWebs {

while ($wit->hasNext()) {
my $w = '';
$w .= '/' if $w;
$w .= '.' if $w;
$w .= $wit->next();
push @webs, $w if $filter->ok($session, $w);
}
Expand All @@ -351,7 +337,7 @@ sub getWebs {
# convert a flat list of webs to a structured parent-child structure;
# the returned hash contains elements of the form
# {
# key => the full webname (e.g. Main/Foo/Bar)
# key => the full webname (e.g. Main.Foo.Bar)
# name => the tail of the webname (e.g. Bar)
# isSubWeb => 1 if the web is a subweb, 0 if it is a top-level web
# parentName => only defined for subwebs
Expand All @@ -368,7 +354,7 @@ sub hashWebs {
# collect all webs
foreach my $key (@webs) {
$webs{$key}{key} = $key;
if ($key =~ /^(.*)\/(.*?)$/) {
if ($key =~ /^(.*)[\/\.](.*?)$/) {
$webs{$key}{isSubWeb} = 1;
$webs{$key}{parentName} = $1;
$webs{$key}{name} = $2;
Expand All @@ -377,7 +363,7 @@ sub hashWebs {
$webs{$key}{isSubWeb} = 0;
$webs{$key}{parentName} = '';
}
$webs{$key}{depth} = ($key =~ tr/\///);
$webs{$key}{depth} = ($key =~ tr/\///) || ($key =~ tr/\.//);
}

# establish parent-child relation
Expand Down
14 changes: 8 additions & 6 deletions lib/Foswiki/Plugins/FlexWebListPlugin/WebFilter.pm
@@ -1,6 +1,6 @@
# Plugin for Foswiki - The Free and Open Source Wiki, http://foswiki.org/
#
# Copyright (C) 2006-2018 Michael Daum http://michaeldaumconsulting.com
# Copyright (C) 2006-2020 Michael Daum http://michaeldaumconsulting.com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
Expand Down Expand Up @@ -44,12 +44,14 @@ sub ok {
return 0 if !$session->webExists($web);

my $webObject = Foswiki::Meta->new($session, $web);
my $thisWebNoSearchAll = Foswiki::isTrue($webObject->getPreference('NOSEARCHALL'), 0);
my $thisWebSiteMapList = Foswiki::isTrue($webObject->getPreference('SITEMAPLIST'), 1);

return 0
if ($this->{public} && $thisWebNoSearchAll) ||
($this->{sitemap} && !$thisWebSiteMapList);
# disabled for performance reasons
#my $thisWebNoSearchAll = Foswiki::isTrue($webObject->getPreference('NOSEARCHALL'), 0);
#my $thisWebSiteMapList = Foswiki::isTrue($webObject->getPreference('SITEMAPLIST'), 1);

#return 0
# if ($this->{public} && $thisWebNoSearchAll) ||
# ($this->{sitemap} && !$thisWebSiteMapList);

return 0 if $this->{allowed} && !$webObject->haveAccess('VIEW');

Expand Down

0 comments on commit b45c666

Please sign in to comment.