[Rt-commit] r4050 - in rt/branches/3.7-EXPERIMENTAL: . sbin

ruz at bestpractical.com ruz at bestpractical.com
Tue Nov 8 08:44:03 EST 2005


Author: ruz
Date: Tue Nov  8 08:43:59 2005
New Revision: 4050

Added:
   rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in
Modified:
   rt/branches/3.7-EXPERIMENTAL/   (props changed)
   rt/branches/3.7-EXPERIMENTAL/configure.ac
Log:
 r1185 at cubic-pc:  cubic | 2005-11-08 16:47:29 +0300
  r1184 at cubic-pc:  cubic | 2005-11-08 01:57:44 +0300
  * sbin/rt-clean-sessions initial commit
 


Modified: rt/branches/3.7-EXPERIMENTAL/configure.ac
==============================================================================
--- rt/branches/3.7-EXPERIMENTAL/configure.ac	(original)
+++ rt/branches/3.7-EXPERIMENTAL/configure.ac	Tue Nov  8 08:43:59 2005
@@ -279,6 +279,7 @@
 		 sbin/rt-dump-database
 		 sbin/rt-setup-database
 		 sbin/rt-test-dependencies
+         sbin/rt-clean-sessions
  		 bin/mason_handler.fcgi
  		 bin/mason_handler.scgi
  		 bin/standalone_httpd

Added: rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in
==============================================================================
--- (empty file)
+++ rt/branches/3.7-EXPERIMENTAL/sbin/rt-clean-sessions.in	Tue Nov  8 08:43:59 2005
@@ -0,0 +1,233 @@
+#!@PERL@
+
+=head1 NAME
+
+rt-clean-sessions - clean old and duplicate RT sessions
+
+=head1 USAGE
+
+    rt-clean-sessions [--debug] [--older <NUM>[H|D|M|Y]]
+
+    rt-clean sessions
+    rt-clean sessions --debug
+    rt-clean sessions --older 10D
+    rt-clean sessions --debug --older 1M
+
+=head1 DESCRIPTION
+
+Script cleans RT sessions from DB or dir with sessions data.
+Leaves in DB only one session per RT user and sessions that aren't older
+than specified(see options).
+
+Script is safe because data in the sessions is only temporary and can be deleted.
+
+=head1 OPTIONS
+
+=head2 older
+
+Date interval in the C<< <NUM>[<unit>] >> format. Default unit is D(ays),
+H(our), M(onth) and Y(ear) are also supported.
+
+For exmaple: C<rt-clean sessions --older 1M> would delete all sessions that are
+older than 1 month.
+
+=head2 debug
+
+Turn on debug output.
+
+=cut
+
+use strict;
+use warnings;
+use lib ("@LOCAL_LIB_PATH@", "@RT_LIB_PATH@");
+
+use Getopt::Long;
+my %opt;
+GetOptions( \%opt, "older=s", "debug" );
+
+if( $opt{'older'} ) {
+    unless( $opt{'older'} =~ /^\s*([0-9]+)\s*(H|D|M|Y)?$/i ) {
+        print STDERR "wrong format of the 'older' argumnet\n";
+        exit(1);
+    }
+    my ($num,$unit) = ($1, uc($2 ||'D'));
+    my %factor = ( H => 60*60 );
+    $factor{'D'} = $factor{'H'}*24;
+    $factor{'M'} = $factor{'D'}*31;
+    $factor{'Y'} = $factor{'D'}*365;
+    $opt{'older'} = $num * $factor{ $unit };
+}
+
+require RT;
+RT::LoadConfig();
+
+if( $opt{'debug'} ) {
+    $RT::LogToScreen = 'debug';
+} else {
+    $RT::LogToScreen = undef;
+}
+
+RT::ConnectToDatabase();
+RT::InitLogging();
+
+if( int($RT::AutoLogoff) || $opt{'older'} ) {
+    my $min;
+    foreach ($RT::AutoLogoff*60, $opt{'older'}) {
+        next unless $_;
+        $min = $_ unless $min;
+        $min = $_ if $_ < $min;
+    }
+
+    clear( $min );
+}
+
+clear_by_user();
+
+exit(0);
+
+my %backends = (
+    mysql	=> 'Apache::Session::MySQL',
+    Pg		=> 'Apache::Session::Postgres',
+);
+
+sub session_attributes
+{
+    return $backends{$RT::DatabaseType} ? {
+            Handle     => $RT::Handle->dbh,
+            LockHandle => $RT::Handle->dbh,
+        } : {
+            Directory     => $RT::MasonSessionDir,
+            LockDirectory => $RT::MasonSessionDir,
+        };
+}
+
+sub session_class
+{
+    no warnings 'once';
+    my $class = $RT::WebSessionClass || $backends{$RT::DatabaseType} || 'Apache::Session::File';
+    eval "require $class";
+    die $@ if $@;
+    return $class;
+}
+
+sub session_ids
+{
+    my $attributes = session_attributes();
+    if( $attributes->{Directory} ) {
+        return _ids_dir( $attributes->{Directory} );
+    } else {
+        return _ids_db( $RT::Handle->dbh );
+    }
+}
+
+sub _ids_dir
+{
+    my $dir = shift;
+    require File::Find;
+    my %file;
+    File::Find::find(
+        sub { return unless /^[a-zA-Z0-9]+$/;
+              $file{$_} = (stat($_))[9];
+            },
+        $dir,
+    );
+
+    return [ sort { $file{$a} <=> $file{$b} } keys %file ];
+}
+
+sub _ids_db
+{
+    my $dbh = shift;
+    my $ids = $dbh->selectcol_arrayref("SELECT id FROM sessions ORDER BY LastUpdated DESC");
+    die "couldn't get ids: ". $dbh->errstr if $dbh->errstr;
+    return $ids;
+}
+
+sub clear
+{
+    my $attributes = session_attributes();
+    if( $attributes->{Directory} ) {
+        return _clear_dir( $attributes->{Directory}, @_ );
+    } else {
+        return _clear_db( $RT::Handle->dbh, @_ );
+    }
+}
+
+sub _clear_db
+{
+    my ($dbh, $older_than) = (shift, shift);
+    my $rows;
+    unless( int $older_than ) {
+        $rows = $dbh->do("DELETE FROM sessions");
+        die "couldn't delete sessions: ". $dbh->errstr unless defined $rows;
+    } else {
+        require POSIX;
+        my $date = POSIX::strftime("%Y-%m-%d %H:%M", localtime( time - int $older_than ) );
+
+        my $sth = $dbh->prepare("DELETE FROM sessions WHERE LastUpdate < ?");
+        die "couldn't prepare query: ". $dbh->errstr unless $sth;
+        $rows = $sth->execute( $date );
+        die "couldn't execute query: ". $dbh->errstr unless defined $rows;
+    }
+
+    $RT::Logger->info("successfuly deleted $rows sessions");
+    return;
+}
+
+sub _clear_dir
+{
+    my ($dir, $older_than) = @_;
+
+    require File::Spec if int $older_than;
+    
+    my $now = time;
+    my $class = session_class();
+    my $attrs = session_attributes();
+
+    foreach my $id( @{ session_ids() } ) {
+        if( int $older_than ) {
+            my $ctime = (stat(File::Spec->catfile($dir,$id)))[9];
+            if( $ctime > $now - $older_than ) {
+                $RT::Logger->debug("skipped session '$id', isn't old");
+                next;
+            }
+        }
+
+        my %session;
+        local $@;
+        eval { tie %session, $class, $id, $attrs };
+        if( $@ ) {
+            $RT::Logger->debug("skipped session '$id', couldn't load: $@");
+            next;
+        }
+        tied(%session)->delete;
+        $RT::Logger->info("successfuly deleted session '$id'");
+    }
+    return;
+}
+
+sub clear_by_user
+{
+    my $class = session_class();
+    my $attrs = session_attributes();
+
+    my %seen = ();
+    foreach my $id( @{ session_ids() } ) {
+        my %session;
+        local $@;
+        eval { tie %session, $class, $id, $attrs };
+        if( $@ ) {
+            $RT::Logger->debug("skipped session '$id', couldn't load: $@");
+            next;
+        }
+        if( $session{'CurrentUser'} && $session{'CurrentUser'}->id ) {
+            unless( $seen{ $session{'CurrentUser'}->id }++ ) {
+                $RT::Logger->debug("skipped session '$id', first user's session");
+                next;
+            }
+        }
+        tied(%session)->delete;
+        $RT::Logger->info("successfuly deleted session '$id'");
+    }
+}
+


More information about the Rt-commit mailing list