MapQueue.java
6.18 KB
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
219
220
221
222
223
224
225
226
package fi.codecrew.moya.beans.map;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.codecrew.moya.beans.map.QueueBeanLocal.MapQueueI;
import fi.codecrew.moya.model.EventMap;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.PlaceSlot;
import fi.codecrew.moya.model.map.MapReservationQueueEntry;
public class MapQueue implements MapQueueI {
private int defaultTimeoutMin = 10;
private int minimumSlotsInQueue = 1;
private int reservingSize = 5;
// private final Set<MapReservationQueueEntry> reserving = new HashSet<>();
private final Set<EventUser> reserving = Collections.newSetFromMap(new ConcurrentHashMap<>());
private final PriorityQueue<MapReservationQueueEntry> queue = new PriorityQueue<>();
private final ConcurrentMap<EventUser, MapReservationQueueEntry> queEntries = new ConcurrentHashMap<>();
private final Integer mapId;
//private final Object reservingLock = new Object();
private static final Logger logger = LoggerFactory.getLogger(MapQueue.class);
public MapQueue(EventMap map) {
this.mapId = map.getId();
}
void timeoutEntries() {
logger.info("Timeouting entries");
// give 10 seconds mercy ( and give us some time to go through all entries)
Date now = new Date(System.currentTimeMillis() + 1000 * 15);
for (EventUser r : reserving) {
MapReservationQueueEntry entry = queEntries.get(r);
logger.info("Checking if should remove user from queue {}, timeout {}", r, entry.getReservationTimeout());
if (entry.getReservationTimeout() == null || now.after(entry.getReservationTimeout())) {
logger.info("Removing Eventuser {} from reserving queue due to reservationTimeout: {}", r, entry.getReservationTimeout());
this.remove(r);
}
}
// Set idle time to the past.
// Idle timeout after 12 seconds
Date idleTimeout = new Date(System.currentTimeMillis() - 1000 * 120);
for (MapReservationQueueEntry entry : queue) {
if (entry.getSeenTime() == null) {
entry.setSeenTime(new Date());
continue;
}
if (idleTimeout.after(entry.getSeenTime())) {
remove(entry.getUser());
}
}
}
public boolean isReserving(EventUser e) {
// Check queue size and add entry to queue
checkReservingEntry();
MapReservationQueueEntry que = queEntries.get(e);
if (que != null) {
que.setSeenTime(new Date());
}
return reserving.contains(e);
}
private final AtomicBoolean modifyReservers = new AtomicBoolean(false);
private void checkReservingEntry() {
if (reserving.size() < getReservingSize() && modifyReservers.compareAndSet(false, true)) {
try {
if (reserving.size() < getReservingSize()) {
MapReservationQueueEntry queEntry = queue.poll();
if (queEntry != null) {
reserving.add(queEntry.getUser());
queEntry.setReservationTimeout(new Date(System.currentTimeMillis() + getDefaultTimeoutMin() * 60 * 1000));
}
}
} finally {
modifyReservers.set(false);
}
}
}
public MapReservationQueueEntry remove(EventUser user) {
if (user == null) {
return null;
}
MapReservationQueueEntry ret = null;
reserving.remove(user);
MapReservationQueueEntry entry = queEntries.remove(user);
if (entry != null) {
// There should neve be more than one instance, but make sure
while (queue.remove(entry)) {
}
}
checkReservingEntry();
return ret;
}
public MapReservationQueueEntry enter(EventUser user, List<PlaceSlot> slots) {
MapReservationQueueEntry ret = initEntry(user, slots);
if (!reserving.contains(user) && !queue.contains(ret)) {
queue.add(ret);
// Check if the user can be put to reservation queue immediately
checkReservingEntry();
} else {
ret = queEntries.get(user);
logger.info("User {} already in queue. Not entering again {}", user, ret);
}
return ret;
}
public void forceAdd(EventUser u, Date time, List<PlaceSlot> slots) {
MapReservationQueueEntry entry = initEntry(u, slots);
entry.setReservationTimeout(time);
queue.remove(entry);
reserving.add(u);
}
private MapReservationQueueEntry initEntry(EventUser user, List<PlaceSlot> slots) {
MapReservationQueueEntry ret = queEntries.get(user);
if (ret == null) {
ret = new MapReservationQueueEntry();
ret.setUser(user);
ret.setSeenTime(new Date());
ret.setPlaceslotcount(slots.size());
MapReservationQueueEntry old = queEntries.putIfAbsent(user, ret);
if (old != null) {
ret = old;
}
}
queEntries.put(user, ret);
return ret;
}
public Integer getPosition(EventUser user) {
Integer ret = null;
MapReservationQueueEntry entry = queEntries.get(user);
if (reserving.contains(user)) {
ret = 0;
logger.info("User in reserving queue {}", user);
} else if (entry != null && queue.contains(entry)) {
ret = 1;
for (Iterator<MapReservationQueueEntry> iterator = queue.iterator(); iterator.hasNext();) {
if (iterator.next().getUser().equals(user)) {
break;
}
++ret;
}
} else {
logger.info("Not in queue, while checking position");
}
return ret;
}
public boolean isInQueue(EventUser user) {
MapReservationQueueEntry entry = queEntries.get(user);
return reserving.contains(user) || (entry != null && queue.contains(entry));
}
public MapReservationQueueEntry getEntry(EventUser user) {
return queEntries.get(user);
}
public Collection<EventUser> getReserving() {
return reserving;
}
@Override
public PriorityQueue<MapReservationQueueEntry> getQueue() {
return queue;
}
public int getMinimumSlotsInQueue() {
return minimumSlotsInQueue;
}
public void setMinimumSlotsInQueue(int minimumSlotsInQueue) {
this.minimumSlotsInQueue = minimumSlotsInQueue;
}
public int getDefaultTimeoutMin() {
return defaultTimeoutMin;
}
public void setDefaultTimeoutMin(int defaultTimeoutMin) {
this.defaultTimeoutMin = defaultTimeoutMin;
}
public int getReservingSize() {
return reservingSize;
}
public void setReservingSize(int reservingSize) {
this.reservingSize = reservingSize;
}
}