Skip to content

memory leak when session save model is "always" #1843

Open
@gabrielsky

Description

@gabrielsky

Describe the bug
version:2.4.3
when a user after logging in , RedisIndexedSessionRepository will add sessionid to redis key:
"sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME" type of set,
the question is if you set save-mode to always, the sessionId will never be remove from this set after you call request.invalidate()

spring.session.redis.save-mode=always

To Reproduce

  1. config
spring.session.redis.save-mode=always
  1. login any user:test, just create sessionId
  2. logout user:test,call request.invalidate()
  3. look data in redis ,the sessionId still in "sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:test"

Expected behavior
when call request.invalidate()
redis remove sessionid from redis set :"sessionAttr:org.springframework.session.FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME:test"

** other **
after set spring.session.redis.save-mode=always
in Reproduce3 put all attributes to this.delta every RedisSession instance

if (this.isNew || (RedisIndexedSessionRepository.this.saveMode == SaveMode.ALWAYS)) {
				getAttributeNames().forEach((attributeName) -> this.delta.put(getSessionAttrNameKey(attributeName),
						cached.getAttribute(attributeName)));
			}

then clean sessionId from redis set

	private void cleanupPrincipalIndex(RedisSession session) {
		String sessionId = session.getId();
		Map<String, String> indexes = RedisIndexedSessionRepository.this.indexResolver.resolveIndexesFor(session);
		String principal = indexes.get(PRINCIPAL_NAME_INDEX_NAME);
		if (principal != null) {
			this.sessionRedisOperations.boundSetOps(getPrincipalKey(principal)).remove(sessionId);
		}
	}

but at last call saveDelta() re add sessionId

private void saveDelta() {
	if (this.delta.isEmpty()) {
		return;
	}
	String sessionId = getId();
	getSessionBoundHashOperations(sessionId).putAll(this.delta);
	String principalSessionKey = getSessionAttrNameKey(
			FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
	String securityPrincipalSessionKey = getSessionAttrNameKey(SPRING_SECURITY_CONTEXT);
	if (this.delta.containsKey(principalSessionKey) || this.delta.containsKey(securityPrincipalSessionKey)) {
		if (this.originalPrincipalName != null) {
			String originalPrincipalRedisKey = getPrincipalKey(this.originalPrincipalName);
			RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(originalPrincipalRedisKey)
					.remove(sessionId);
		}
		Map<String, String> indexes = RedisIndexedSessionRepository.this.indexResolver.resolveIndexesFor(this);
		String principal = indexes.get(PRINCIPAL_NAME_INDEX_NAME);
		this.originalPrincipalName = principal;
		if (principal != null) {
			String principalRedisKey = getPrincipalKey(principal);
			RedisIndexedSessionRepository.this.sessionRedisOperations.boundSetOps(principalRedisKey)
					.add(sessionId);
		}
	}

	this.delta = new HashMap<>(this.delta.size());

	Long originalExpiration = (this.originalLastAccessTime != null)
			? this.originalLastAccessTime.plus(getMaxInactiveInterval()).toEpochMilli() : null;
	RedisIndexedSessionRepository.this.expirationPolicy.onExpirationUpdated(originalExpiration, this);
}

Please help to check whether there is this problem

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions