@Override public MemcachedBackupSession newMemcachedBackupSession() { return new MemcachedBackupSession( this ); }
@Override public void changeSessionId( final Session session ) { // e.g. invoked by the AuthenticatorBase (for BASIC auth) on login to prevent session fixation // so that session backup won't be omitted we must store this event super.changeSessionId( session ); ((MemcachedBackupSession)session).setSessionIdChanged( true ); }
private void checkSession(final MemcachedBackupSession actual, final MemcachedBackupSession expected) { assertNotNull(actual); assertEquals(actual.getId(), expected.getId()); assertEquals(actual.getAttributesInternal(), expected.getAttributesInternal()); } }
/** * Is invoked when a session was removed from the manager, e.g. because the * session has been invalidated. * * Is used to release a lock if the non-stick session was locked * * It's also used to keep track of such sessions in non-sticky mode, so that * lockingStrategy.onBackupWithoutLoadedSession is not invoked (see issue 116). * * @param session the removed session. */ public void sessionRemoved(final MemcachedBackupSession session) { if(!_sticky) { if(session.isLocked()) { _lockingStrategy.releaseLock(session.getIdInternal()); session.releaseLock(); } _invalidSessionsCache.put(session.getIdInternal(), Boolean.TRUE); } }
final MemcachedBackupSession session = (MemcachedBackupSession) s; if ( _log.isDebugEnabled() ) { _log.debug( "Checking session " + session.getId() + ": " + "\n- isValid: " + session.isValidInternal() + "\n- isExpiring: " + session.isExpiring() + "\n- isBackupRunning: " + session.isBackupRunning() + "\n- isExpirationUpdateRunning: " + session.isExpirationUpdateRunning() + "\n- wasAccessedSinceLastBackup: " + session.wasAccessedSinceLastBackup() + "\n- memcachedExpirationTime: " + session.getMemcachedExpirationTime() ); if ( session.isValidInternal() && !session.isExpiring() && !session.isBackupRunning() && !session.isExpirationUpdateRunning() && session.wasAccessedSinceLastBackup() && session.getMaxInactiveInterval() > 0 // for <= 0 the session was stored in memcached with expiration 0 && session.getMemcachedExpirationTime() <= 2 * delay ) { try { _backupSessionService.updateExpiration( session ); } catch ( final Throwable e ) { _log.info( "Could not update expiration in memcached for session " + session.getId(), e );
private void assertSessionFields( final MemcachedBackupSession session, final MemcachedBackupSession deserialized ) { Assert.assertEquals( session.getCreationTimeInternal(), deserialized.getCreationTimeInternal() ); Assert.assertEquals( session.getLastAccessedTimeInternal(), deserialized.getLastAccessedTimeInternal() ); Assert.assertEquals( session.getMaxInactiveInterval(), deserialized.getMaxInactiveInterval() ); Assert.assertEquals( session.isNewInternal(), deserialized.isNewInternal() ); Assert.assertEquals( session.isValidInternal(), deserialized.isValidInternal() ); Assert.assertEquals( session.getThisAccessedTimeInternal(), deserialized.getThisAccessedTimeInternal() ); Assert.assertEquals( session.getLastBackupTime(), deserialized.getLastBackupTime() ); Assert.assertEquals( session.getIdInternal(), deserialized.getIdInternal() ); Assert.assertEquals( session.getAuthType(), deserialized.getAuthType() ); assertDeepEquals( session.getPrincipal(), deserialized.getPrincipal() ); }
session.setNew( true ); session.setValid( true ); session.setCreationTime( System.currentTimeMillis() ); session.setMaxInactiveInterval( _manager.isMaxInactiveIntervalSet() ? _manager.getMaxInactiveInterval() : _manager.getContext().getSessionTimeout() * 60 ); session.setId( sessionId ); session.registerReference(); _log.debug( "Created new session with id " + session.getId() ); if( _invalidSessionsCache.containsKey(session.getId()) ){ if ( _log.isDebugEnabled() ) { _log.debug( "Remove session id " + session.getId() + " from _invalidSessionsCache, marking new session valid" ); _invalidSessionsCache.remove(session.getId());
public BackupResult call() throws Exception { if ( _log.isDebugEnabled() ) { _log.debug( "Starting for session id " + _session.getId() ); _session.setBackupRunning( true ); try { final ConcurrentMap<String, Object> attributes = _session.getAttributesFiltered(); final byte[] attributesData = serializeAttributes( _session, attributes ); final int hashCode = Arrays.hashCode( attributesData ); final BackupResult result; if ( _session.getDataHashCode() != hashCode || _force || _session.authenticationChanged() ) { _session.setLastBackupTime( System.currentTimeMillis() ); final byte[] data = _transcoderService.serialize( _session, attributesData ); _session.setDataHashCode( hashCode ); case FAILURE: _statistics.requestWithBackupFailure(); _session.backupFailed(); break; case SKIPPED: _statistics.requestWithoutSessionModification(); _session.storeThisAccessedTimeFromLastBackupCheck(); break; case SUCCESS:
session.access(); session.endAccess(); session.setAttribute( "foo", "bar" ); _service.backupSession( session.getIdInternal(), false, null ).get(); verify( _memcachedMock, times( 1 ) ).set( eq( session.getId() ), anyInt(), any(), any( Transcoder.class ) ); session.access(); session.endAccess(); session.setAttribute( "foo", "bar" ); session.setAttribute( "bar", "baz" ); _service.backupSession( session.getIdInternal(), false, null ).get(); verify( _memcachedMock, times( 2 ) ).set( eq( session.getId() ), anyInt(), any(), any( Transcoder.class ) ); _service.backupSession( session.getIdInternal(), false, null ).get(); verify( _memcachedMock, times( 2 ) ).set( eq( session.getId() ), anyInt(), any(), any( Transcoder.class ) );
if ( !msmSession.isValidInternal() ) { if(_log.isDebugEnabled()) _log.debug( "Non valid session found in session map for " + sessionId ); if ( msmSession.releaseReference() > 0 ) { if(_log.isDebugEnabled()) _log.debug( "Session " + sessionId + " is still used by another request, skipping backup and (optional) lock handling/release." ); return new SimpleFuture<BackupResult>( BackupResult.SKIPPED ); msmSession.passivate(); _manager.removeInternal( msmSession, false ); final boolean force = sessionIdChanged || msmSession.isSessionIdChanged() || !_sticky && (msmSession.getSecondsSinceLastBackup() >= msmSession.getMaxInactiveInterval()); final Future<BackupResult> result = _backupSessionService.backupSession( msmSession, force );
@Nonnull final BackupSessionService backupSessionService ) { if ( !_sessionIdFormat.isValid( session.getIdInternal() ) ) { return; final int maxInactiveInterval = session.getMaxInactiveInterval(); final byte[] validityData = encode( maxInactiveInterval, session.getLastAccessedTimeInternal(), session.getThisAccessedTimeInternal() ); final String validityKey = _sessionIdFormat.createValidityInfoKeyName( session.getIdInternal() ); _log.debug( "Stored session validity info for session " + session.getIdInternal() );
_log.debug( "Starting for session id " + session.getId() ); try { if ( !_memcachedNodesManager.getSessionIdFormat().isValid( session.getId() ) ) { if ( _log.isDebugEnabled() ) { _log.debug( "Skipping backup for session id " + session.getId() + " as the session id is not usable for memcached." ); if ( !session.wasAccessedSinceLastBackupCheck() && !force ) { _log.debug( "Session was not accessed since last backup/check, therefore we can skip this" ); if ( !session.attributesAccessedSinceLastBackup() && !force && !session.authenticationChanged() && !session.isNewInternal() ) { _log.debug( "Session attributes were not accessed since last backup/check, therefore we can skip this" ); _statistics.requestWithoutAttributesAccess(); } catch ( final Exception e ) { if ( _log.isInfoEnabled() ) { _log.info( "Could not store session " + session.getId() + " in memcached.", e );
/** * Test that session attribute serialization and hash calculation is only * performed if the session and its attributes were accessed since the last backup/backup check. * Otherwise this computing time shall be saved for a better world :-) * @throws ExecutionException * @throws InterruptedException */ @Test public void testOnlyHashAttributesOfAccessedSessionsAndAttributes() throws InterruptedException, ExecutionException { final TranscoderService transcoderServiceMock = mock( TranscoderService.class ); @SuppressWarnings( "unchecked" ) final ConcurrentMap<String, Object> anyMap = any( ConcurrentMap.class ); when( transcoderServiceMock.serializeAttributes( any( MemcachedBackupSession.class ), anyMap ) ).thenReturn( new byte[0] ); _service.setTranscoderService( transcoderServiceMock ); final MemcachedBackupSession session = createSession( _service ); session.setAttribute( "foo", "bar" ); _service.backupSession( session.getIdInternal(), false, null ).get(); verify( transcoderServiceMock, times( 1 ) ).serializeAttributes( eq( session ), eq( session.getAttributesInternal() ) ); // we need some millis between last backup and next access (due to check in BackupSessionService) Thread.sleep(5L); session.access(); session.getAttribute( "foo" ); _service.backupSession( session.getIdInternal(), false, null ).get(); verify( transcoderServiceMock, times( 2 ) ).serializeAttributes( eq( session ), eq( session.getAttributesInternal() ) ); // we need some millis between last backup and next access (due to check in BackupSessionService) Thread.sleep(5L); _service.backupSession( session.getIdInternal(), false, null ).get(); verify( transcoderServiceMock, times( 2 ) ).serializeAttributes( eq( session ), eq( session.getAttributesInternal() ) ); }
session.setMaxInactiveInterval( -1 ); session.access(); session.endAccess(); session.setAttribute( "foo", "bar" ); final String sessionId = session.getId();
@Test public void testBackupSessionInCouchbase() throws InterruptedException, ExecutionException { final MemcachedSessionService service = _tomcat1.getService(); final MemcachedBackupSession session = createSession( service ); final String sessionId = "12345"; session.setId(sessionId); session.setAttribute( "foo", "bar" ); final BackupResult backupResult = service.backupSession( session.getIdInternal(), false, null ).get(); assertEquals(backupResult.getStatus(), BackupResultStatus.SUCCESS); final MemcachedBackupSession loadedSession = transcoderService.deserialize(mc.get(sessionId, ByteArrayTranscoder.INSTANCE), _tomcat1.getManager()); checkSession(loadedSession, session); }
private void storeSessionInMemcached( final MemcachedBackupSession session, final byte[] data) throws InterruptedException, ExecutionException, TimeoutException { /* calculate the expiration time (instead of using just maxInactiveInterval), as * this is relevant for the update of the expiration time: if we would just use * maxInactiveInterval, the session would exist longer in memcached than it would * be valid in tomcat */ final int expirationTime = session.getMemcachedExpirationTimeToSet(); final long start = System.currentTimeMillis(); try { final Future<Boolean> future = _storage.set( _memcachedNodesManager.getStorageKeyFormat().format(session.getId()), toMemcachedExpiration(expirationTime), data ); if ( !_sessionBackupAsync ) { future.get( _sessionBackupTimeout, TimeUnit.MILLISECONDS ); session.setLastMemcachedExpirationTime( expirationTime ); session.setLastBackupTime( System.currentTimeMillis() ); } else { /* in async mode, we asume the session was stored successfully */ session.setLastMemcachedExpirationTime( expirationTime ); session.setLastBackupTime( System.currentTimeMillis() ); } } finally { _statistics.registerSince( MEMCACHED_UPDATE, start ); } }
_log.debug( "Updating expiration time for session " + session.getId() ); if ( !_memcachedNodesManager.getSessionIdFormat().isValid( session.getId() ) ) { return; session.setExpirationUpdateRunning( true ); session.setLastBackupTime( System.currentTimeMillis() ); try { final ConcurrentMap<String, Object> attributes = session.getAttributesFiltered(); final byte[] attributesData = _transcoderService.serializeAttributes( session, attributes ); final byte[] data = _transcoderService.serialize( session, attributesData ); createBackupSessionTask( session, true ).doBackupSession( session, data, attributesData ); } finally { session.setExpirationUpdateRunning( false );
if ( session != null && session.isValid() ) { final String newSessionId = _memcachedNodesManager.getNewSessionIdIfNodeFromSessionIdUnavailable( session.getId() ); if ( newSessionId != null ) { _log.debug( "Session needs to be relocated, setting new id on session..." ); session.setIdForRelocate( newSessionId ); _statistics.requestWithMemcachedFailover(); return newSessionId; final MemcachedBackupSession backupSession = loadBackupSession( requestedSessionId ); if ( backupSession != null ) { _log.debug( "Loaded backup session for " + requestedSessionId + ", adding locally with "+ backupSession.getIdInternal() +"." ); addValidLoadedSession( backupSession, true ); _statistics.requestWithMemcachedFailover(); return backupSession.getId();
private void pingSessionBackup( @Nonnull final MemcachedBackupSession session ) throws InterruptedException { final String key = _sessionIdFormat.createBackupKey( session.getId() ); final Future<Boolean> touchResultFuture = _storage.add( key, 5, BYTE_1 ); try { final boolean touchResult = touchResultFuture.get(_manager.getOperationTimeout(), TimeUnit.MILLISECONDS); if ( touchResult ) { _log.warn( "The secondary backup for session " + session.getIdInternal() + " should be touched in memcached, but it seemed to be" + " not existing. Will store in memcached again." ); saveSessionBackup( session, key ); } else _log.debug( "The secondary session backup was ping'ed successfully." ); } catch ( final TimeoutException e ) { _log.warn( "The secondary backup for session " + session.getIdInternal() + " could not be completed within " + _manager.getOperationTimeout() + " millis, was cancelled now." ); } catch ( final ExecutionException e ) { _log.warn( "An exception occurred when trying to ping session " + session.getIdInternal(), e ); } }
assertNotNull(session.getId()); Future<BackupResult> result = _service.backupSession(session.getId(), false, "unused"); assertFalse(_service.getManager().getSessionsInternal().containsKey(session.getId())); _service.getTrackingHostValve().storeRequestThreadLocal(requestMock); when(_memcachedMock.get(eq(session.getId()), any(Transcoder.class))).thenReturn(transcoderService.serialize(session)); final MemcachedBackupSession session2 = _service.findSession(session.getId()); assertTrue(session2.isLocked()); assertEquals(session2.getRefCount(), 1); session2.setAttribute("foo", "bar"); result = _service.backupSession(session.getId(), false, null); _service.getTrackingHostValve().resetRequestThreadLocal(); assertEquals(result.get().getStatus(), BackupResultStatus.SKIPPED); assertTrue(_service.getManager().getSessionsInternal().containsKey(session.getId())); assertEquals(session2.getRefCount(), 1);