📄 terracottasessionmanager.java
字号:
{ super(request); _sessionData = new SessionData(getClusterId(), _maxIdleMs); _lastAccessed = _sessionData.getCreationTime(); } protected Session(SessionData sd) { super(sd.getCreationTime(), sd.getId()); _sessionData = sd; _lastAccessed = getLastAccessedTime(); initValues(); } public SessionData getSessionData() { return _sessionData; } @Override public long getCookieSetTime() { return _sessionData.getCookieTime(); } @Override protected void cookieSet() { _sessionData.setCookieTime(getLastAccessedTime()); } @Override public void setMaxInactiveInterval(int secs) { super.setMaxInactiveInterval(secs); if(_maxIdleMs > 0L && _maxIdleMs / 10L < (long)_scavengePeriodMs) { long newScavengeSecs = (secs + 9) / 10; setScavengePeriodMs(1000L * newScavengeSecs); } // Update the estimated expiration time if (secs < 0) { this._sessionData._expiration.value = -1L; } else { this._sessionData._expiration.value = System.currentTimeMillis() + (1000L * secs); } } @Override public long getLastAccessedTime() { if (!isValid()) throw new IllegalStateException(); return _sessionData.getPreviousAccessTime(); } @Override public long getCreationTime() throws IllegalStateException { if (!isValid()) throw new IllegalStateException(); return _sessionData.getCreationTime(); } // Overridden for visibility @Override protected String getClusterId() { return super.getClusterId(); } protected Map newAttributeMap() { // It is important to never return a new attribute map here (as other Session implementations do), // but always return the shared attributes map, so that a new session created on a different cluster // node is immediately filled with the session data from Terracotta. return _sessionData.getAttributeMap(); } @Override protected void access(long time) { // The local previous access time is always updated via the super.access() call. // If the requests are steady and within the scavenge period, the distributed shared access times // are never updated. If only one node gets hits, other nodes reach the expiration time and the // scavenging on other nodes will believe the session is expired, since the distributed shared // access times have never been updated. // Therefore we need to update the distributed shared access times once in a while, no matter what. long previousAccessTime = getPreviousAccessTime(); if (time - previousAccessTime > getScavengePeriodMs()) { Log.debug("Out-of-date update of distributed access times: previous {} - current {}", previousAccessTime, time); updateAccessTimes(time); } else { if (time - _lastUpdate > getScavengePeriodMs()) { Log.debug("Periodic update of distributed access times: last update {} - current {}", _lastUpdate, time); updateAccessTimes(time); } else { Log.debug("Skipping update of distributed access times: previous {} - current {}", previousAccessTime, time); } } super.access(time); } /** * Updates the shared distributed access times that need to be updated * * @param time the update value */ private void updateAccessTimes(long time) { _sessionData.setPreviousAccessTime(_accessed); if (getMaxIdlePeriodMs() > 0) _sessionData.setExpirationTime(time + getMaxIdlePeriodMs()); _lastUpdate = time; } // Overridden for visibility @Override protected void timeout() { super.timeout(); Log.debug("Timed out session {} with id {}", this, getClusterId()); } @Override public void invalidate() { super.invalidate(); Log.debug("Invalidated session {} with id {}", this, getClusterId()); } private long getMaxIdlePeriodMs() { return _maxIdleMs; } private long getPreviousAccessTime() { return super.getLastAccessedTime(); } } /** * The session data that is distributed to cluster nodes via Terracotta. */ public static class SessionData { private final String _id; private final Map _attributes; private final long _creation; private final MutableLong _expiration; private long _previousAccess; private long _cookieTime; public SessionData(String sessionId, long maxIdleMs) { _id = sessionId; // Don't need synchronization, as we grab a distributed session id lock // when this map is accessed. _attributes = new HashMap(); _creation = System.currentTimeMillis(); _expiration = new MutableLong(); _previousAccess = _creation; // Set expiration time to negative value if the session never expires _expiration.value = maxIdleMs > 0 ? _creation + maxIdleMs : -1L; } public String getId() { return _id; } protected Map getAttributeMap() { return _attributes; } public long getCreationTime() { return _creation; } public long getExpirationTime() { return _expiration.value; } public void setExpirationTime(long time) { _expiration.value = time; } public long getCookieTime() { return _cookieTime; } public void setCookieTime(long time) { _cookieTime = time; } public long getPreviousAccessTime() { return _previousAccess; } public void setPreviousAccessTime(long time) { _previousAccess = time; } } protected static class Lock { private static final ThreadLocal<Map<String, Integer>> nestings = new ThreadLocal<Map<String, Integer>>() { @Override protected Map<String, Integer> initialValue() { return new HashMap<String, Integer>(); } }; private Lock() { } public static void lock(String lockId) { Integer nestingLevel = nestings.get().get(lockId); if (nestingLevel == null) nestingLevel = 0; if (nestingLevel < 0) throw new AssertionError("Lock(" + lockId + ") nest level = " + nestingLevel + ", thread " + Thread.currentThread() + ": " + getLocks()); if (nestingLevel == 0) { ManagerUtil.beginLock(lockId, Manager.LOCK_TYPE_WRITE); Log.debug("Lock({}) acquired by thread {}", lockId, Thread.currentThread().getName()); } nestings.get().put(lockId, nestingLevel + 1); Log.debug("Lock({}) nestings {}", lockId, getLocks()); } public static boolean tryLock(String lockId) { boolean result = ManagerUtil.tryBeginLock(lockId, Manager.LOCK_TYPE_WRITE); Log.debug("Lock({}) tried and" + (result ? "" : " not") + " acquired by thread {}", lockId, Thread.currentThread().getName()); if (result) { Integer nestingLevel = nestings.get().get(lockId); if (nestingLevel == null) nestingLevel = 0; nestings.get().put(lockId, nestingLevel + 1); Log.debug("Lock({}) nestings {}", lockId, getLocks()); } return result; } public static void unlock(String lockId) { Integer nestingLevel = nestings.get().get(lockId); if (nestingLevel == null) return; if (nestingLevel < 1) throw new AssertionError("Lock(" + lockId + ") nest level = " + nestingLevel + ", thread " + Thread.currentThread() + ": " + getLocks()); if (nestingLevel == 1) { ManagerUtil.commitLock(lockId); Log.debug("Lock({}) released by thread {}", lockId, Thread.currentThread().getName()); nestings.get().remove(lockId); } else { nestings.get().put(lockId, nestingLevel - 1); } Log.debug("Lock({}) nestings {}", lockId, getLocks()); } /** * For testing and debugging purposes only. * @return the lock ids held by the current thread */ protected static Map<String, Integer> getLocks() { return Collections.unmodifiableMap(nestings.get()); } } private static class MutableLong { private long value; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -