forked from wildfly/wildfly
-
Notifications
You must be signed in to change notification settings - Fork 0
/
FineSessionFactory.java
218 lines (197 loc) · 13.1 KB
/
FineSessionFactory.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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
* JBoss, Home of Professional Open Source.
* Copyright 2013, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.wildfly.clustering.web.infinispan.session.fine;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.infinispan.Cache;
import org.infinispan.context.Flag;
import org.wildfly.clustering.ee.infinispan.CacheEntryMutator;
import org.wildfly.clustering.ee.infinispan.MutableCacheEntry;
import org.wildfly.clustering.ee.infinispan.Mutator;
import org.wildfly.clustering.infinispan.spi.distribution.Key;
import org.wildfly.clustering.marshalling.jboss.InvalidSerializedFormException;
import org.wildfly.clustering.marshalling.jboss.MarshalledValue;
import org.wildfly.clustering.marshalling.jboss.Marshaller;
import org.wildfly.clustering.marshalling.jboss.MarshallingContext;
import org.wildfly.clustering.web.LocalContextFactory;
import org.wildfly.clustering.web.infinispan.logging.InfinispanWebLogger;
import org.wildfly.clustering.web.infinispan.session.InfinispanImmutableSession;
import org.wildfly.clustering.web.infinispan.session.InfinispanSession;
import org.wildfly.clustering.web.infinispan.session.MutableSessionAccessMetaData;
import org.wildfly.clustering.web.infinispan.session.MutableSessionCreationMetaData;
import org.wildfly.clustering.web.infinispan.session.SessionAccessMetaData;
import org.wildfly.clustering.web.infinispan.session.SessionAccessMetaDataKey;
import org.wildfly.clustering.web.infinispan.session.SessionCreationMetaData;
import org.wildfly.clustering.web.infinispan.session.SessionCreationMetaDataEntry;
import org.wildfly.clustering.web.infinispan.session.SessionCreationMetaDataKey;
import org.wildfly.clustering.web.infinispan.session.SessionFactory;
import org.wildfly.clustering.web.infinispan.session.SimpleSessionAccessMetaData;
import org.wildfly.clustering.web.infinispan.session.SimpleSessionCreationMetaData;
import org.wildfly.clustering.web.infinispan.session.SimpleSessionMetaData;
import org.wildfly.clustering.web.session.ImmutableSession;
import org.wildfly.clustering.web.session.ImmutableSessionAttributes;
import org.wildfly.clustering.web.session.ImmutableSessionMetaData;
import org.wildfly.clustering.web.session.Session;
import org.wildfly.clustering.web.session.SessionAttributes;
import org.wildfly.clustering.web.session.SessionContext;
import org.wildfly.clustering.web.session.SessionMetaData;
/**
* {@link SessionFactory} for fine granularity sessions.
* A given session is mapped to N+2 co-located cache entries, where N is the number of session attributes:
* One cache entry containing the static session meta data and local context, one containing the dynamic session meta data,
* and one cache entry per session attribute.
* @author Paul Ferraro
*/
public class FineSessionFactory<L> implements SessionFactory<FineSessionEntry<L>, L> {
private final Cache<SessionCreationMetaDataKey, SessionCreationMetaDataEntry<L>> creationMetaDataCache;
private final Cache<SessionCreationMetaDataKey, SessionCreationMetaDataEntry<L>> findCreationMetaDataCache;
private final Cache<SessionAccessMetaDataKey, SessionAccessMetaData> accessMetaDataCache;
private final Cache<SessionAttributeKey, MarshalledValue<Object, MarshallingContext>> attributeCache;
private final SessionContext context;
private final Marshaller<Object, MarshalledValue<Object, MarshallingContext>, MarshallingContext> marshaller;
private final LocalContextFactory<L> localContextFactory;
private final Predicate<Map.Entry<SessionAttributeKey, MarshalledValue<Object, MarshallingContext>>> invalidAttribute;
private final boolean requireMarshallable;
@SuppressWarnings("unchecked")
public FineSessionFactory(Cache<? extends Key<String>, ?> cache, SessionContext context, Marshaller<Object, MarshalledValue<Object, MarshallingContext>, MarshallingContext> marshaller, LocalContextFactory<L> localContextFactory, boolean lockOnRead, boolean requireMarshallable) {
this.creationMetaDataCache = (Cache<SessionCreationMetaDataKey, SessionCreationMetaDataEntry<L>>) cache;
this.findCreationMetaDataCache = lockOnRead ? this.creationMetaDataCache.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK) : this.creationMetaDataCache;
this.accessMetaDataCache = (Cache<SessionAccessMetaDataKey, SessionAccessMetaData>) cache;
this.attributeCache = (Cache<SessionAttributeKey, MarshalledValue<Object, MarshallingContext>>) cache;
this.context = context;
this.marshaller = marshaller;
this.localContextFactory = localContextFactory;
this.requireMarshallable = requireMarshallable;
this.invalidAttribute = entry -> {
try {
this.marshaller.read(entry.getValue());
return false;
} catch (InvalidSerializedFormException e) {
InfinispanWebLogger.ROOT_LOGGER.failedToActivateSessionAttribute(e, entry.getKey().getValue(), entry.getKey().getAttribute());
return true;
}
};
}
@Override
public Session<L> createSession(String id, FineSessionEntry<L> entry) {
MutableCacheEntry<SessionCreationMetaData> creationMetaDataEntry = entry.getMutableSessionCreationMetaDataEntry();
MutableCacheEntry<SessionAccessMetaData> accessMetaDataEntry = entry.getMutableSessionAccessMetaDataEntry();
SessionCreationMetaData creationMetaData = new MutableSessionCreationMetaData(creationMetaDataEntry.getValue(), creationMetaDataEntry.getMutator());
SessionAccessMetaData accessMetaData = new MutableSessionAccessMetaData(accessMetaDataEntry.getValue(), accessMetaDataEntry.getMutator());
SessionMetaData metaData = new SimpleSessionMetaData(creationMetaData, accessMetaData);
SessionAttributes attributes = new FineSessionAttributes<>(id, this.attributeCache, this.marshaller, this.requireMarshallable);
return new InfinispanSession<>(id, metaData, attributes, entry.getLocalContext(), this.localContextFactory, this.context, this);
}
@Override
public ImmutableSession createImmutableSession(String id, FineSessionEntry<L> entry) {
SessionCreationMetaData creationMetaData = entry.getMutableSessionCreationMetaDataEntry().getValue();
SessionAccessMetaData accessMetaData = entry.getMutableSessionAccessMetaDataEntry().getValue();
ImmutableSessionMetaData metaData = new SimpleSessionMetaData(creationMetaData, accessMetaData);
ImmutableSessionAttributes attributes = new FineImmutableSessionAttributes<>(id, this.attributeCache, this.marshaller);
return new InfinispanImmutableSession(id, metaData, attributes, this.context);
}
@Override
public FineSessionEntry<L> createValue(String id, Void context) {
SessionCreationMetaDataKey creationMetaDataKey = new SessionCreationMetaDataKey(id);
SessionCreationMetaDataEntry<L> creationMetaDataEntry = new SessionCreationMetaDataEntry<>(new SimpleSessionCreationMetaData());
SessionCreationMetaDataEntry<L> existingCreationMetaDataEntry = this.creationMetaDataCache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).putIfAbsent(creationMetaDataKey, creationMetaDataEntry);
Mutator creationMetaDataMutator = Mutator.PASSIVE;
if (existingCreationMetaDataEntry != null) {
creationMetaDataEntry = existingCreationMetaDataEntry;
creationMetaDataMutator = new CacheEntryMutator<>(this.creationMetaDataCache, creationMetaDataKey, creationMetaDataEntry);
}
SessionAccessMetaDataKey accessMetaDataKey = new SessionAccessMetaDataKey(id);
SessionAccessMetaData accessMetaData = new SimpleSessionAccessMetaData();
Mutator accessMetaDataMutator = Mutator.PASSIVE;
if (existingCreationMetaDataEntry == null) {
this.accessMetaDataCache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).put(accessMetaDataKey, accessMetaData);
} else {
SessionAccessMetaData existingAccessMetaData = this.accessMetaDataCache.getAdvancedCache().withFlags(Flag.FORCE_SYNCHRONOUS).putIfAbsent(accessMetaDataKey, accessMetaData);
if (existingAccessMetaData != null) {
accessMetaData = existingAccessMetaData;
accessMetaDataMutator = new CacheEntryMutator<>(this.accessMetaDataCache, accessMetaDataKey, accessMetaData);
}
}
if (existingCreationMetaDataEntry != null) {
// Preemptively read all attributes to detect invalid session attributes
if (this.attributeCache.getAdvancedCache().getGroup(id).entrySet().stream().filter(entry -> ((Map.Entry<?, ?>) entry).getKey() instanceof SessionAttributeKey).anyMatch(this.invalidAttribute)) {
this.remove(id);
return this.createValue(id, context);
}
}
return new FineSessionEntry<>(new MutableCacheEntry<>(creationMetaDataEntry.getMetaData(), creationMetaDataMutator), new MutableCacheEntry<>(accessMetaData, accessMetaDataMutator), creationMetaDataEntry.getLocalContext());
}
@Override
public FineSessionEntry<L> tryValue(String id) {
return this.getValue(id, this.findCreationMetaDataCache.getAdvancedCache().withFlags(Flag.FAIL_SILENTLY));
}
@Override
public FineSessionEntry<L> findValue(String id) {
return this.getValue(id, this.findCreationMetaDataCache);
}
public FineSessionEntry<L> getValue(String id, Cache<SessionCreationMetaDataKey, SessionCreationMetaDataEntry<L>> creationMetaDataCache) {
SessionCreationMetaDataKey creationMetaDataKey = new SessionCreationMetaDataKey(id);
SessionCreationMetaDataEntry<L> creationMetaDataEntry = creationMetaDataCache.get(creationMetaDataKey);
if (creationMetaDataEntry != null) {
Mutator creationMetaDataMutator = new CacheEntryMutator<>(this.creationMetaDataCache, creationMetaDataKey, creationMetaDataEntry);
SessionAccessMetaDataKey accessMetaDataKey = new SessionAccessMetaDataKey(id);
SessionAccessMetaData accessMetaData = this.accessMetaDataCache.get(accessMetaDataKey);
if (accessMetaData != null) {
Mutator accessMetaDataMutator = new CacheEntryMutator<>(this.accessMetaDataCache, accessMetaDataKey, accessMetaData);
// Preemptively read all attributes to detect invalid session attributes
if (this.attributeCache.getAdvancedCache().getGroup(id).entrySet().stream().filter(entry -> ((Map.Entry<?, ?>) entry).getKey() instanceof SessionAttributeKey).anyMatch(this.invalidAttribute)) {
// Invalidate
this.remove(id);
return null;
}
return new FineSessionEntry<>(new MutableCacheEntry<>(creationMetaDataEntry.getMetaData(), creationMetaDataMutator), new MutableCacheEntry<>(accessMetaData, accessMetaDataMutator), creationMetaDataEntry.getLocalContext());
}
// Remove orphaned entries
this.attributeCache.getAdvancedCache().withFlags(Flag.SKIP_LISTENER_NOTIFICATION).removeGroup(id);
}
return null;
}
@Override
public void remove(final String id) {
this.creationMetaDataCache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).remove(new SessionCreationMetaDataKey(id));
this.accessMetaDataCache.getAdvancedCache().withFlags(Flag.IGNORE_RETURN_VALUES).remove(new SessionAccessMetaDataKey(id));
this.attributeCache.getAdvancedCache().removeGroup(id);
}
@Override
public void evict(final String id) {
try {
this.creationMetaDataCache.evict(new SessionCreationMetaDataKey(id));
this.accessMetaDataCache.evict(new SessionAccessMetaDataKey(id));
Consumer<SessionAttributeKey> evictor = key -> {
try {
this.attributeCache.evict(key);
} catch (Throwable e) {
InfinispanWebLogger.ROOT_LOGGER.failedToPassivateSessionAttribute(e, id, key.getAttribute());
}
};
this.attributeCache.getAdvancedCache().withFlags(Flag.SKIP_CACHE_LOAD).getGroup(id).keySet().stream().filter((Object key) -> key instanceof SessionAttributeKey).forEach(evictor);
} catch (Throwable e) {
InfinispanWebLogger.ROOT_LOGGER.failedToPassivateSession(e, id);
}
}
}