{"action":"created","issue":{"url":"https://api.github.com/repos/hazelcast/hazelcast/issues/7291","labels_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/7291/labels{/name}","comments_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/7291/comments","events_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/7291/events","html_url":"https://github.com/hazelcast/hazelcast/issues/7291","id":125954559,"number":7291,"title":"WebFilter(3.6-RC1): session attributes being lost/overwritten with old values using deferred-write by reading them","user":{"login":"dfex55","id":7135062,"avatar_url":"https://avatars.githubusercontent.com/u/7135062?v=3","gravatar_id":"","url":"https://api.github.com/users/dfex55","html_url":"https://github.com/dfex55","followers_url":"https://api.github.com/users/dfex55/followers","following_url":"https://api.github.com/users/dfex55/following{/other_user}","gists_url":"https://api.github.com/users/dfex55/gists{/gist_id}","starred_url":"https://api.github.com/users/dfex55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dfex55/subscriptions","organizations_url":"https://api.github.com/users/dfex55/orgs","repos_url":"https://api.github.com/users/dfex55/repos","events_url":"https://api.github.com/users/dfex55/events{/privacy}","received_events_url":"https://api.github.com/users/dfex55/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/hazelcast/hazelcast/labels/Team:%20Integration","name":"Team: Integration","color":"fef2c0"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2016-01-11T14:21:55Z","updated_at":"2016-01-14T09:14:28Z","closed_at":null,"body":"Assume two parallel http requests A and B, sticky-session set to false, deferred-write to true:\r\n\r\n__Time tick 1:__\r\nA: reads attributes X=1 and Y=1 from session\r\n\r\n__Time tick 2:__\r\nA: sets attribute X=2\r\n\r\n__Time tick 3:__\r\nB: reads attributes X=1 and Y=1 from session\r\n\r\n__Time tick 4:__\r\nB: sets attribute Y= 2\r\n\r\n__Time tick 5:__\r\nA: request finished. WebFilter \"commits\" session to distributed map\r\n\r\nNote:\r\nDistributed map contains X=2 and Y=1\r\n\r\n__Time tick 6:__\r\nB: request finished. WebFilter \"commits\" session to distributed map\r\n\r\nThe distributed map now contains Y=2 but again the old X=1 that was read by B but was never set. X=2 is overwritten and the data is lost.\r\n\r\nThe expected behavior is, that attributes which were only read and not modified, will not be written to the distributed map.\r\n\r\nIn general:\r\nReading attributes with deferred-write enabled, triggers a write operation for that value in the distributed map (maybe only, when another attribute was changed - not tested). All other changes to that value after the value was read, are overwritten.\r\n\r\nQuestion regarding performance:\r\nIf you check many (lets say a few 10k values) session attributes via getAttribute (deferred-write is enabled), will all these values be written to the distributed map? It might be, that we are hitting this performance bug. Only 2-3 attributes are changed, but thousands are written to the map."},"comment":{"url":"https://api.github.com/repos/hazelcast/hazelcast/issues/comments/171581446","html_url":"https://github.com/hazelcast/hazelcast/issues/7291#issuecomment-171581446","issue_url":"https://api.github.com/repos/hazelcast/hazelcast/issues/7291","id":171581446,"user":{"login":"dfex55","id":7135062,"avatar_url":"https://avatars.githubusercontent.com/u/7135062?v=3","gravatar_id":"","url":"https://api.github.com/users/dfex55","html_url":"https://github.com/dfex55","followers_url":"https://api.github.com/users/dfex55/followers","following_url":"https://api.github.com/users/dfex55/following{/other_user}","gists_url":"https://api.github.com/users/dfex55/gists{/gist_id}","starred_url":"https://api.github.com/users/dfex55/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dfex55/subscriptions","organizations_url":"https://api.github.com/users/dfex55/orgs","repos_url":"https://api.github.com/users/dfex55/repos","events_url":"https://api.github.com/users/dfex55/events{/privacy}","received_events_url":"https://api.github.com/users/dfex55/received_events","type":"User","site_admin":false},"created_at":"2016-01-14T09:14:28Z","updated_at":"2016-01-14T09:14:28Z","body":"Same test without reading the unchanged attribute, everything is fine:\r\n\r\n\r\n\r\n__first run:__\r\n[#| 14.01.2016 10:07:09.837  | Connector+Servlet-Thread-Pool-20 | DEBUG A\r\nRequest A, read from session: x: 1\r\n|#]\r\n\r\n[#| 14.01.2016 10:07:09.838 | Connector+Servlet-Thread-Pool-20 | DEBUG A\r\nRequest A, setAttribute x: 2\r\n|#]\r\n\r\n\r\n[#| 14.01.2016 10:07:11.618 | Connector+Servlet-Thread-Pool-16 | DEBUG B\r\nRequest B, read from session: y: 3\r\n|#]\r\n\r\n[#| 14.01.2016 10:07:11.618 | Connector+Servlet-Thread-Pool-16 | DEBUG B\r\nRequest B, setAttribute y: 4\r\n|#]\r\n\r\n__second run:__\r\n\r\n[#| 14.01.2016 10:07:20.561 | Connector+Servlet-Thread-Pool-22 | DEBUG A\r\nRequest A, read from session: x: 2\r\n|#]\r\n\r\n[#| 14.01.2016 10:07:20.561 | Connector+Servlet-Thread-Pool-22 | DEBUG A\r\nRequest A, setAttribute x: 3\r\n|#]\r\n\r\n[#| 14.01.2016 10:07:22.632 | Connector+Servlet-Thread-Pool-23 | DEBUG B\r\nRequest B, read from session: y: 4\r\n|#]\r\n\r\n[#| 14.01.2016 10:07:22.632 | Connector+Servlet-Thread-Pool-23 | DEBUG B\r\nRequest B, setAttribute y: 5\r\n|#]\r\n\r\n\r\n\r\nCode:\r\n\r\nA:\r\n```java\r\n    Logger logger = LoggerFactory.getLogger(this.getClass());\r\n\r\n    Integer x = (Integer) httpSession.getAttribute(\"x\");\r\n\r\n    logger.debug(\"Request A, read from session: x: {}\", x);\r\n\r\n    if (x == null) {\r\n      x = 0;\r\n    }\r\n    x++;\r\n\r\n    httpSession.setAttribute(\"x\", x);\r\n\r\n    logger.debug(\"Request A, setAttribute x: {}\", x);\r\n\r\n    Thread.sleep(5000);\r\n```\r\n\r\n\r\nB:\r\n```java\r\n    Logger logger = LoggerFactory.getLogger(this.getClass());\r\n\r\n    Integer y = (Integer) httpSession.getAttribute(\"y\");\r\n\r\n    logger.debug(\"Request B, read from session: y: {}\", y);\r\n\r\n    if (y == null) {\r\n      y = 0;\r\n    }\r\n    y++;\r\n\r\n    httpSession.setAttribute(\"y\", y);\r\n\r\n    logger.debug(\"Request B, setAttribute y: {}\", y);\r\n\r\n    Thread.sleep(5000);\r\n```\r\n"}}