Use atomic move to rename the session file When a session is written to disk, it's done in a temporary file and then renamed (moved) to its final name. This rename was done in 2 operations (or 3 if file already exist and need to be deleted first), copy then delete. Make use of the ATOMIC_MOVE option to prevent multiple operations but mainly to fix a concurrency issue which leads to a NoSuchFileException. When user is first login in, it's not possible to have 2 concurrent requests trying to write the same session file but when session is one hour old or reached half of its max age, the next http request will refresh the session. Then it's possible that 2 (or more) concurrent requests end up trying to rename their temp file to the same session file. Since the move was not an atomic operation, the first request was deleting session file in order to rename its temp file but right after the delete and before the temp one was renamed, the second request also was also trying to delete the session file and it was failing with NoSuchFileException. Change-Id: I8b045244e4fb3062401ce916d7cae33f255413bf
diff --git a/src/main/java/com/googlesource/gerrit/plugins/websession/flatfile/FlatFileWebSessionCache.java b/src/main/java/com/googlesource/gerrit/plugins/websession/flatfile/FlatFileWebSessionCache.java index 23aa194..8d12bb2 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/websession/flatfile/FlatFileWebSessionCache.java +++ b/src/main/java/com/googlesource/gerrit/plugins/websession/flatfile/FlatFileWebSessionCache.java
@@ -149,7 +149,8 @@ ObjectOutputStream objStream = new ObjectOutputStream(fileStream)) { objStream.writeObject(value); Files.move(tempFile, tempFile.resolveSibling(key), - StandardCopyOption.REPLACE_EXISTING); + StandardCopyOption.REPLACE_EXISTING, + StandardCopyOption.ATOMIC_MOVE); } } catch (IOException e) { log.warn("Cannot put into cache " + dir, e);