SessionTrackerImpl
SessionImpl
// 會話id,超時時間
SessionImpl(long sessionId, int timeout)
{
this.sessionId = sessionId;
this.timeout = timeout;
isClosing = false;
}
// 會話id
final long sessionId;
// 超時時間
final int timeout;
// 關閉標志
boolean isClosing;
// 擁有者
Object owner;
public long getSessionId()
{
return sessionId;
}
public int getTimeout()
{
return timeout;
}
public boolean isClosing()
{
return isClosing;
}
public String toString()
{
return "0x" + Long.toHexString(sessionId);
}
SessionTrackerImpl
// 基于當前時間&傳入id構造新的會話id
public static long initializeNextSessionId(long id)
{
long nextSid;
nextSid = (Time.currentElapsedTime() << 24) >>> 8;
nextSid = nextSid | (id << 56);
if (nextSid == EphemeralType.CONTAINER_EPHEMERAL_OWNER)
{
++nextSid;
}
return nextSid;
}
public SessionTrackerImpl(
SessionExpirer expirer,
ConcurrentMap<Long, Integer> sessionsWithTimeout,
int tickTime,
long serverId,
ZooKeeperServerListener listener)
{
super("SessionTracker", listener);
this.expirer = expirer;
this.sessionExpiryQueue = new ExpiryQueue<SessionImpl>(tickTime);
this.sessionsWithTimeout = sessionsWithTimeout;
this.nextSessionId.set(initializeNextSessionId(serverId));
for (Entry<Long, Integer> e : sessionsWithTimeout.entrySet())
{
trackSession(e.getKey(), e.getValue());
}
EphemeralType.validateServerId(serverId);
}
volatile boolean running = true;
public void dumpSessions(PrintWriter pwriter)
{
pwriter.print("Session ");
sessionExpiryQueue.dump(pwriter);
}
// 時間點--在此時間點會超期的會話id集合
public synchronized Map<Long, Set<Long>> getSessionExpiryMap()
{
Map<Long, Set<SessionImpl>> expiryMap = sessionExpiryQueue.getExpiryMap();
Map<Long, Set<Long>> sessionExpiryMap = new TreeMap<Long, Set<Long>>();
for (Entry<Long, Set<SessionImpl>> e : expiryMap.entrySet())
{
Set<Long> ids = new HashSet<Long>();
sessionExpiryMap.put(e.getKey(), ids);
for (SessionImpl s : e.getValue())
{
ids.add(s.sessionId);
}
}
return sessionExpiryMap;
}
@Override
public String toString()
{
StringWriter sw = new StringWriter();
PrintWriter pwriter = new PrintWriter(sw);
dumpSessions(pwriter);
pwriter.flush();
pwriter.close();
return sw.toString();
}
@Override
public void run()
{
try
{
while (running)
{
// 獲取下一超期時間點距離現在時長
long waitTime = sessionExpiryQueue.getWaitTime();
if (waitTime > 0)
{
Thread.sleep(waitTime);
continue;
}
// 對每個超期的會話,設定狀態為關閉中
// 讓會話超期
for (SessionImpl s : sessionExpiryQueue.poll())
{
ServerMetrics.getMetrics().STALE_SESSIONS_EXPIRED.add(1);
setSessionClosing(s.sessionId);
expirer.expire(s);
}
}
}
catch (InterruptedException e)
{
handleException(this.getName(), e);
}
LOG.info("SessionTrackerImpl exited loop!");
}
// 觸碰會話
public synchronized boolean touchSession(long sessionId, int timeout)
{
// 會話物件
SessionImpl s = sessionsById.get(sessionId);
if (s == null)
{
logTraceTouchInvalidSession(sessionId, timeout);
return false;
}
if (s.isClosing())
{
logTraceTouchClosingSession(sessionId, timeout);
return false;
}
// 為會話設定新的超期時間點
updateSessionExpiry(s, timeout);
return true;
}
// 為會話設定新的超期時間點
private void updateSessionExpiry(SessionImpl s, int timeout)
{
logTraceTouchSession(s.sessionId, timeout, "");
sessionExpiryQueue.update(s, timeout);
}
private void logTraceTouchSession(long sessionId, int timeout, String sessionStatus)
{
if (LOG.isTraceEnabled())
{
String msg = MessageFormat.format(
"SessionTrackerImpl --- Touch {0}session: 0x{1} with timeout {2}", sessionStatus,
Long.toHexString(sessionId), Integer.toString(timeout));
ZooTrace.logTraceMessage(LOG, ZooTrace.CLIENT_PING_TRACE_MASK, msg);
}
}
private void logTraceTouchInvalidSession(long sessionId, int timeout)
{
logTraceTouchSession(sessionId, timeout, "invalid ");
}
private void logTraceTouchClosingSession(long sessionId, int timeout)
{
logTraceTouchSession(sessionId, timeout, "closing ");
}
// 獲得會話的超期時間點
public int getSessionTimeout(long sessionId)
{
return sessionsWithTimeout.get(sessionId);
}
// 設定會話物件關閉標志
public synchronized void setSessionClosing(long sessionId)
{
if (LOG.isTraceEnabled())
{
LOG.trace("Session closing: 0x{}", Long.toHexString(sessionId));
}
SessionImpl s = sessionsById.get(sessionId);
if (s == null)
{
return;
}
s.isClosing = true;
}
public synchronized void removeSession(long sessionId)
{
LOG.debug("Removing session 0x{}", Long.toHexString(sessionId));
// 容器1中移除會話
SessionImpl s = sessionsById.remove(sessionId);
// 容器2中移除會話
sessionsWithTimeout.remove(sessionId);
if (LOG.isTraceEnabled())
{
ZooTrace.logTraceMessage(LOG,
ZooTrace.SESSION_TRACE_MASK, "SessionTrackerImpl --- Removing session 0x" +
Long.toHexString(sessionId));
}
if (s != null)
{
// 容器3中移除會話
sessionExpiryQueue.remove(s);
}
}
public void shutdown()
{
LOG.info("Shutting down");
running = false;
if (LOG.isTraceEnabled())
{
ZooTrace.logTraceMessage(LOG, ZooTrace.getTextTraceLevel(), "Shutdown SessionTrackerImpl!");
}
}
// 分配會話id,超期時間
public long createSession(int sessionTimeout)
{
long sessionId = nextSessionId.getAndIncrement();
trackSession(sessionId, sessionTimeout);
return sessionId;
}
@Override
public synchronized boolean trackSession(long id, int sessionTimeout)
{
boolean added = false;
// 會話物件
SessionImpl session = sessionsById.get(id);
if (session == null)
{
session = new SessionImpl(id, sessionTimeout);
}
// 會話容器1
SessionImpl existedSession = sessionsById.putIfAbsent(id, session);
if (existedSession != null)
{
session = existedSession;
}
else
{
added = true;
LOG.debug("Adding session 0x{}", Long.toHexString(id));
}
if (LOG.isTraceEnabled())
{
String actionStr = added ? "Adding" : "Existing";
ZooTrace.logTraceMessage(LOG, ZooTrace.SESSION_TRACE_MASK, "SessionTrackerImpl --- "
+ actionStr + " session 0x" + Long.toHexString(id) + " " + sessionTimeout);
}
// 更新會話下一超期時間點
updateSessionExpiry(session, sessionTimeout);
return added;
}
public synchronized boolean commitSession(long id, int sessionTimeout)
{
// 會話容器2
return sessionsWithTimeout.put(id, sessionTimeout) == null;
}
public boolean isTrackingSession(long sessionId)
{
return sessionsById.containsKey(sessionId);
}
public synchronized void checkSession(
long sessionId, Object owner)
throws KeeperException.SessionExpiredException,
KeeperException.SessionMovedException, KeeperException.UnknownSessionException
{
LOG.debug("Checking session 0x{}", Long.toHexString(sessionId));
// 獲得會話物件
SessionImpl session = sessionsById.get(sessionId);
if (session == null)
{
throw new KeeperException.UnknownSessionException();
}
if (session.isClosing())
{
throw new KeeperException.SessionExpiredException();
}
// 設定會話擁有者
if (session.owner == null)
{
session.owner = owner;
}
else if (session.owner != owner)
{
throw new KeeperException.SessionMovedException();
}
}
public synchronized void setOwner(long id, Object owner) throws SessionExpiredException
{
SessionImpl session = sessionsById.get(id);
if (session == null || session.isClosing())
{
throw new KeeperException.SessionExpiredException();
}
session.owner = owner;
}
// 檢查會話
public void checkGlobalSession(
long sessionId, Object owner)
throws KeeperException.SessionExpiredException, KeeperException.SessionMovedException
{
try
{
checkSession(sessionId, owner);
}
catch (KeeperException.UnknownSessionException e)
{
throw new KeeperException.SessionExpiredException();
}
}
// 本地會話個數
public long getLocalSessionCount()
{
return 0;
}
// 支持本地會話
@Override
public boolean isLocalSessionsEnabled()
{
return false;
}
// 全域會話id資訊
public Set<Long> globalSessions()
{
return sessionsById.keySet();
}
// 本地會話
public Set<Long> localSessions()
{
return Collections.emptySet();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/421691.html
標籤:其他
上一篇:對于服務治理概念的一些總結和理解,我們應該如何實踐服務治理
下一篇:初學RabbitMQ(一)
