Apache-ASP

 view release on metacpan or  search on metacpan

lib/Apache/ASP/StateManager.pm  view on Meta::CPAN

	    if(my $count = $member_state->Delete()) {
		$asp->{dbg} && 
		  $asp->Debug("deleting session", {
						   session_id => $id, 
						   files_deleted => $count,
						  });
		$deleted++;
		delete $internal->{$id};
	    } else {
		$asp->Error("can't delete session id: $id");
		return; # no next in eval {}
	    }
	};
	if($@) {
	    $asp->Error("error for cleanup of session id $id: $@");
	}
    }
    $internal->UNLOCK();

    #### LEAVE DIRECTORIES, NASTY RACE CONDITION POTENTIAL
    ## NOW PRUNE ONLY DIRECTORIES THAT WE DON'T NEED TO KEEP
    ## FOR PERFORMANCE
    # REMOVE DIRECTORY, LOCK 
    # if the directory is still empty, remove it, lock it 
    # down so no new sessions will be created in it while we 
    # are testing
    if($deleted == @$ids) {
	if ($state->GroupId !~ /^[0]/) {
	    $asp->{Internal}->LOCK();
	    my $ids = $state->GroupMembers();
	    if(@{$ids} == 0) {
		$self->Log("purging stale group ".$state->GroupId.", which should only happen ".
			   "after Apache::ASP upgrade to beyond 2.09");
		$state->DeleteGroupId();
	    }
	    $asp->{Internal}->UNLOCK();
	}
    }

    $deleted;
}

sub CleanupGroups {
    my($self, $force) = @_;
    return unless $self->{Session};

    my $cleanup = 0;
    my $state_dir = $self->{state_dir};
    my $internal = $self->{Internal};
    $force ||= 0;

    $self->Debug("forcing groups cleanup") if ($self->{dbg} && $force);

    # each apache process has an internal time in which it 
    # did its last check, once we have passed that, we check
    # $Internal for the last time the check was done.  We
    # break it up in this way so that locking on $Internal
    # does not become another bottleneck for scripts
    if($force || ($Apache::ASP::CleanupGroups{$state_dir} || 0) < time()) {
	# /8 to keep it less bursty... since we check groups every group_refresh/2
	# we'll average 1/4 of the groups everytime we check them on a busy server
	$Apache::ASP::CleanupGroups{$state_dir} = time() + $self->{group_refresh}/8;
	$self->{dbg} && $self->Debug("testing internal time for cleanup groups");
	if($self->CleanupMaster) {
	    $internal->LOCK();
	    if($force || ($internal->{CleanupGroups} < (time - $self->{group_refresh}/8))) {
		$internal->{CleanupGroups} = time;
		$cleanup = 1;
	    }
	    $internal->UNLOCK;
	}
    }
    return unless $cleanup;

    # clean cache, so caching won't affect CleanupGroups() being called multiple times
    $self->{internal_cached_keys} = undef;

    # only one process doing CleanupGroup at a time now, so OK
    # lock around, necessary when keeping empty group directories
    my $groups = $self->{Session}{_SELF}{'state'}->DefaultGroups();
    $self->{dbg} && $self->Debug("groups ", $groups);
    my($sum_active, $sum_deleted);
    $internal->LOCK();
    my $start_cleanup = time;
    for(@{$groups}) {
	$sum_deleted = $self->CleanupGroup($_, $force);
	if ($start_cleanup > time) {
	    # every second, take a breather in the lock management
	    # so that sessions can be created, and the like, so for 
	    # long purges, the application will get sticky in 1 second
	    # bursts
	    $start_cleanup = time;
	    $internal->UNLOCK;
	    $internal->LOCK;
	    last unless $self->CleanupMaster;
	}
    }
    $internal->UNLOCK();
    $self->{dbg} && $self->Debug("cleanup groups", { deleted => $sum_deleted }) if $self->{dbg};

    # boolean true at least for master
    $sum_deleted || 1; 
}

sub CleanupMaster {
    my $self = shift;
    my $internal = $self->{Internal};
    
    $internal->LOCK;
    my $master = $internal->{CleanupMaster} || 
      {
       ServerID => '',
       PID => 0,
       Checked => 0,       
      };

    my $is_master = (($master->{ServerID} eq $ServerID) and ($master->{PID} eq $$)) ? 1 : 0;
    $self->{dbg} && $self->Debug(current_master => $master, is_master => $is_master );
    my $stale_time = $is_master ? $self->{group_refresh} / 4 : 
      $self->{group_refresh} / 2 + int($self->{group_refresh} * rand() / 2) + 1;
    $stale_time += $master->{Checked};



( run in 1.010 second using v1.01-cache-2.11-cpan-39bf76dae61 )