/
DefaultSessionCache.java
197 lines (175 loc) · 5.64 KB
/
DefaultSessionCache.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
//
// ========================================================================
// Copyright (c) 1995-2021 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.server.session;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.statistic.CounterStatistic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* DefaultSessionCache
*
* A session store that keeps its sessions in memory within a concurrent map
*/
@ManagedObject
public class DefaultSessionCache extends AbstractSessionCache
{
private static final Logger LOG = LoggerFactory.getLogger(DefaultSessionCache.class);
/**
* The cache of sessions in a concurrent map
*/
private final ConcurrentMap<String, Session> _sessions;
private final CounterStatistic _stats = new CounterStatistic();
/**
* @param manager The SessionHandler related to this SessionCache
*/
public DefaultSessionCache(SessionHandler manager)
{
this(manager, new ConcurrentHashMap<>());
}
/**
* @param manager The SessionHandler related to this SessionCache
* @param sessionMap The session map implementation to use
*/
public DefaultSessionCache(SessionHandler manager, ConcurrentMap<String, Session> sessionMap)
{
super(manager);
this._sessions = sessionMap;
}
/**
* @return the number of sessions in the cache
*/
@ManagedAttribute(value = "current sessions in cache", readonly = true)
public long getSessionsCurrent()
{
return _stats.getCurrent();
}
/**
* @return the max number of sessions in the cache
*/
@ManagedAttribute(value = "max sessions in cache", readonly = true)
public long getSessionsMax()
{
return _stats.getMax();
}
/**
* @return a running total of sessions in the cache
*/
@ManagedAttribute(value = "total sessions in cache", readonly = true)
public long getSessionsTotal()
{
return _stats.getTotal();
}
@ManagedOperation(value = "reset statistics", impact = "ACTION")
public void resetStats()
{
_stats.reset();
}
@Override
public Session doGet(String id)
{
if (id == null)
return null;
return _sessions.get(id);
}
@Override
public Session doPutIfAbsent(String id, Session session)
{
Session s = _sessions.putIfAbsent(id, session);
if (s == null)
_stats.increment();
return s;
}
@Override
protected Session doComputeIfAbsent(String id, Function<String, Session> mappingFunction)
{
return _sessions.computeIfAbsent(id, k ->
{
Session s = mappingFunction.apply(k);
if (s != null)
_stats.increment();
return s;
});
}
@Override
public Session doDelete(String id)
{
Session s = _sessions.remove(id);
if (s != null)
_stats.decrement();
return s;
}
@Override
public void shutdown()
{
if (LOG.isDebugEnabled())
LOG.debug("Shutdown sessions, invalidating = {}", isInvalidateOnShutdown());
// loop over all the sessions in memory (a few times if necessary to catch sessions that have been
// added while we're running
int loop = 100;
while (!_sessions.isEmpty() && loop-- > 0)
{
for (Session session : _sessions.values())
{
if (isInvalidateOnShutdown())
{
//not preserving sessions on exit
try
{
session.invalidate();
}
catch (Exception e)
{
LOG.trace("IGNORED", e);
}
}
else
{
//write out the session and remove from the cache
if (_sessionDataStore.isPassivating())
session.willPassivate();
try
{
_sessionDataStore.store(session.getId(), session.getSessionData());
}
catch (Exception e)
{
LOG.warn("Unable to store {}", session, e);
}
doDelete(session.getId()); //remove from memory
session.setResident(false);
}
}
}
}
@Override
public Session newSession(HttpServletRequest request, SessionData data)
{
return new Session(getSessionHandler(), request, data);
}
@Override
public Session newSession(SessionData data)
{
return new Session(getSessionHandler(), data);
}
@Override
public boolean doReplace(String id, Session oldValue, Session newValue)
{
return _sessions.replace(id, oldValue, newValue);
}
}