spring-projects / spring-projects/spring-session

memory leak when session save model is "always"

Open
#1,843 5 comments 0 reactions 1 assignee View on GitHub

@eleftherias is already working on this.

Since Oct 19, 2021.

in: redis type: bug
Dominant language
Java
Stars
1.9k
Forks
1.2k
Avg merge
4h 27m
Merged PRs (30d)
55

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.