2614 |
29 Aug 14 |
nicklas |
1 |
package net.sf.basedb.reggie; |
2614 |
29 Aug 14 |
nicklas |
2 |
|
2614 |
29 Aug 14 |
nicklas |
3 |
import java.util.HashMap; |
2614 |
29 Aug 14 |
nicklas |
4 |
import java.util.Iterator; |
2614 |
29 Aug 14 |
nicklas |
5 |
import java.util.Map; |
2614 |
29 Aug 14 |
nicklas |
6 |
|
4881 |
03 Jul 18 |
nicklas |
7 |
import net.sf.basedb.core.DbControl; |
4881 |
03 Jul 18 |
nicklas |
8 |
import net.sf.basedb.core.TransactionalAction; |
4881 |
03 Jul 18 |
nicklas |
9 |
|
2614 |
29 Aug 14 |
nicklas |
10 |
/** |
4306 |
17 Jan 17 |
nicklas |
Simple implementation for keeping track of reserved "items" for a dedicated |
2614 |
29 Aug 14 |
nicklas |
amount of time. After the given timeout expires the items are considered |
2614 |
29 Aug 14 |
nicklas |
removed. |
2614 |
29 Aug 14 |
nicklas |
14 |
|
2614 |
29 Aug 14 |
nicklas |
@since 2.16 |
2614 |
29 Aug 14 |
nicklas |
16 |
*/ |
2614 |
29 Aug 14 |
nicklas |
17 |
public class ReservedItems<I> |
2614 |
29 Aug 14 |
nicklas |
18 |
{ |
2614 |
29 Aug 14 |
nicklas |
19 |
|
4889 |
06 Jul 18 |
nicklas |
20 |
private final Map<I, Reservation> reserve; |
2614 |
29 Aug 14 |
nicklas |
21 |
private final long timeout; |
2614 |
29 Aug 14 |
nicklas |
22 |
private long nextCleanup; |
2614 |
29 Aug 14 |
nicklas |
23 |
|
2614 |
29 Aug 14 |
nicklas |
24 |
/** |
2614 |
29 Aug 14 |
nicklas |
Create a new reserved cache with the given timeout. |
2614 |
29 Aug 14 |
nicklas |
@param timeout Timeout in seconds |
2614 |
29 Aug 14 |
nicklas |
27 |
*/ |
2614 |
29 Aug 14 |
nicklas |
28 |
public ReservedItems(int timeout) |
2614 |
29 Aug 14 |
nicklas |
29 |
{ |
2614 |
29 Aug 14 |
nicklas |
30 |
this.timeout = timeout * 1000; |
2614 |
29 Aug 14 |
nicklas |
31 |
this.nextCleanup = System.currentTimeMillis() + 10 * this.timeout; |
4889 |
06 Jul 18 |
nicklas |
32 |
this.reserve = new HashMap<I, Reservation>(); |
2614 |
29 Aug 14 |
nicklas |
33 |
} |
2614 |
29 Aug 14 |
nicklas |
34 |
|
2614 |
29 Aug 14 |
nicklas |
35 |
/** |
2614 |
29 Aug 14 |
nicklas |
Try to reserve the given item. If it is not currently |
2614 |
29 Aug 14 |
nicklas |
reserved, a new reservation is made and TRUE is returned. |
2614 |
29 Aug 14 |
nicklas |
If the item is already reserved, FALSE is returned. |
4889 |
06 Jul 18 |
nicklas |
The DbControl parameter is optional, but if it is used |
4889 |
06 Jul 18 |
nicklas |
the reservation can be replaced before the timeout if |
4889 |
06 Jul 18 |
nicklas |
this method is called again with a different DbControl |
4889 |
06 Jul 18 |
nicklas |
created from the same session. |
4889 |
06 Jul 18 |
nicklas |
@since 4.19 |
2614 |
29 Aug 14 |
nicklas |
44 |
*/ |
4889 |
06 Jul 18 |
nicklas |
45 |
public synchronized boolean reserve(DbControl dc, I item) |
2614 |
29 Aug 14 |
nicklas |
46 |
{ |
2614 |
29 Aug 14 |
nicklas |
47 |
long now = System.currentTimeMillis(); |
2614 |
29 Aug 14 |
nicklas |
48 |
|
4889 |
06 Jul 18 |
nicklas |
49 |
Reservation newReservation = new Reservation(now + timeout, dc); |
4889 |
06 Jul 18 |
nicklas |
50 |
Reservation existingReservation = reserve.get(item); |
4889 |
06 Jul 18 |
nicklas |
51 |
if (existingReservation != null && existingReservation.timeout > now) |
2614 |
29 Aug 14 |
nicklas |
52 |
{ |
2614 |
29 Aug 14 |
nicklas |
// The item is reserved and has not timed out |
4889 |
06 Jul 18 |
nicklas |
// If it the SAME session, but DIFFERENT transaction |
4889 |
06 Jul 18 |
nicklas |
// we allow the reservation to override |
4889 |
06 Jul 18 |
nicklas |
56 |
if (!existingReservation.canBeReplacedWith(newReservation)) |
4889 |
06 Jul 18 |
nicklas |
57 |
{ |
4889 |
06 Jul 18 |
nicklas |
58 |
return false; |
4889 |
06 Jul 18 |
nicklas |
59 |
} |
2614 |
29 Aug 14 |
nicklas |
60 |
} |
2614 |
29 Aug 14 |
nicklas |
61 |
|
2614 |
29 Aug 14 |
nicklas |
// Reserve the given item |
4889 |
06 Jul 18 |
nicklas |
63 |
reserve.put(item, newReservation); |
2614 |
29 Aug 14 |
nicklas |
64 |
|
2614 |
29 Aug 14 |
nicklas |
// Do cleanup if it was a long time ago |
2614 |
29 Aug 14 |
nicklas |
66 |
if (now > nextCleanup) cleanUp(); |
2614 |
29 Aug 14 |
nicklas |
67 |
|
2614 |
29 Aug 14 |
nicklas |
68 |
return true; |
2614 |
29 Aug 14 |
nicklas |
69 |
} |
2614 |
29 Aug 14 |
nicklas |
70 |
|
4881 |
03 Jul 18 |
nicklas |
71 |
/** |
4881 |
03 Jul 18 |
nicklas |
Release the reserved item. |
4881 |
03 Jul 18 |
nicklas |
@since 4.19 |
4881 |
03 Jul 18 |
nicklas |
74 |
*/ |
4881 |
03 Jul 18 |
nicklas |
75 |
public synchronized void release(I item) |
4881 |
03 Jul 18 |
nicklas |
76 |
{ |
4881 |
03 Jul 18 |
nicklas |
77 |
reserve.remove(item); |
4881 |
03 Jul 18 |
nicklas |
78 |
} |
4881 |
03 Jul 18 |
nicklas |
79 |
|
4881 |
03 Jul 18 |
nicklas |
80 |
/** |
4881 |
03 Jul 18 |
nicklas |
Releases the reserved item if the transaction is rolled back. |
4881 |
03 Jul 18 |
nicklas |
@since 4.19 |
4881 |
03 Jul 18 |
nicklas |
83 |
*/ |
4881 |
03 Jul 18 |
nicklas |
84 |
public void releaseIfTransactionFails(DbControl dc, I item) |
4881 |
03 Jul 18 |
nicklas |
85 |
{ |
4881 |
03 Jul 18 |
nicklas |
86 |
dc.addTransactionalAction(new ReleaseAtEndOfTransaction(item, false, true)); |
4881 |
03 Jul 18 |
nicklas |
87 |
} |
4881 |
03 Jul 18 |
nicklas |
88 |
|
4881 |
03 Jul 18 |
nicklas |
89 |
/** |
4881 |
03 Jul 18 |
nicklas |
Releases the reserved item when the transactions ended (no matter if it |
4881 |
03 Jul 18 |
nicklas |
is committed or rolled back). |
4881 |
03 Jul 18 |
nicklas |
@since 4.19 |
4881 |
03 Jul 18 |
nicklas |
93 |
*/ |
4881 |
03 Jul 18 |
nicklas |
94 |
public void releaseAtEndOfTransaction(DbControl dc, I item) |
4881 |
03 Jul 18 |
nicklas |
95 |
{ |
4881 |
03 Jul 18 |
nicklas |
96 |
dc.addTransactionalAction(new ReleaseAtEndOfTransaction(item, true, true)); |
4881 |
03 Jul 18 |
nicklas |
97 |
} |
4881 |
03 Jul 18 |
nicklas |
98 |
|
2614 |
29 Aug 14 |
nicklas |
99 |
private void cleanUp() |
2614 |
29 Aug 14 |
nicklas |
100 |
{ |
2614 |
29 Aug 14 |
nicklas |
101 |
long now = System.currentTimeMillis(); |
4889 |
06 Jul 18 |
nicklas |
102 |
Iterator<Reservation> it = reserve.values().iterator(); |
2614 |
29 Aug 14 |
nicklas |
103 |
while (it.hasNext()) |
2614 |
29 Aug 14 |
nicklas |
104 |
{ |
4889 |
06 Jul 18 |
nicklas |
105 |
if (it.next().timeout < now) it.remove(); |
2614 |
29 Aug 14 |
nicklas |
106 |
} |
2614 |
29 Aug 14 |
nicklas |
107 |
nextCleanup = now + 10 * timeout; |
2614 |
29 Aug 14 |
nicklas |
108 |
} |
2614 |
29 Aug 14 |
nicklas |
109 |
|
4889 |
06 Jul 18 |
nicklas |
110 |
public void debug() |
4889 |
06 Jul 18 |
nicklas |
111 |
{ |
4889 |
06 Jul 18 |
nicklas |
112 |
System.out.println("reserved: " + reserve); |
4889 |
06 Jul 18 |
nicklas |
113 |
} |
4889 |
06 Jul 18 |
nicklas |
114 |
|
4889 |
06 Jul 18 |
nicklas |
115 |
static class Reservation |
4889 |
06 Jul 18 |
nicklas |
116 |
{ |
4889 |
06 Jul 18 |
nicklas |
117 |
final long timeout; |
4889 |
06 Jul 18 |
nicklas |
118 |
final String sessionId; |
4889 |
06 Jul 18 |
nicklas |
119 |
final int transactionId; |
4889 |
06 Jul 18 |
nicklas |
120 |
|
4889 |
06 Jul 18 |
nicklas |
121 |
Reservation(long timeout, DbControl dc) |
4889 |
06 Jul 18 |
nicklas |
122 |
{ |
4889 |
06 Jul 18 |
nicklas |
123 |
this.timeout = timeout; |
4889 |
06 Jul 18 |
nicklas |
124 |
this.sessionId = dc != null ? dc.getSessionControl().getId() : null; |
4889 |
06 Jul 18 |
nicklas |
125 |
this.transactionId = dc != null ? dc.hashCode() : 0; |
4889 |
06 Jul 18 |
nicklas |
126 |
} |
4889 |
06 Jul 18 |
nicklas |
127 |
|
4889 |
06 Jul 18 |
nicklas |
128 |
/** |
4889 |
06 Jul 18 |
nicklas |
Check if this reservation can be replaced with the other |
4889 |
06 Jul 18 |
nicklas |
reservation. This is allowed if both reservations have |
4889 |
06 Jul 18 |
nicklas |
the same session id but different transaction id. |
4889 |
06 Jul 18 |
nicklas |
132 |
*/ |
4889 |
06 Jul 18 |
nicklas |
133 |
boolean canBeReplacedWith(Reservation other) |
4889 |
06 Jul 18 |
nicklas |
134 |
{ |
4889 |
06 Jul 18 |
nicklas |
135 |
return sessionId != null && sessionId.equals(other.sessionId) && transactionId != other.transactionId; |
4889 |
06 Jul 18 |
nicklas |
136 |
} |
4889 |
06 Jul 18 |
nicklas |
137 |
|
4889 |
06 Jul 18 |
nicklas |
138 |
@Override |
4889 |
06 Jul 18 |
nicklas |
139 |
public String toString() |
4889 |
06 Jul 18 |
nicklas |
140 |
{ |
4889 |
06 Jul 18 |
nicklas |
141 |
return timeout + "[" + sessionId + "@" + transactionId + "]"; |
4889 |
06 Jul 18 |
nicklas |
142 |
} |
4889 |
06 Jul 18 |
nicklas |
143 |
} |
4889 |
06 Jul 18 |
nicklas |
144 |
|
4881 |
03 Jul 18 |
nicklas |
145 |
/** |
4881 |
03 Jul 18 |
nicklas |
Callback handler for releasing items when a transaction is committed and/or rolled back. |
4881 |
03 Jul 18 |
nicklas |
147 |
*/ |
4881 |
03 Jul 18 |
nicklas |
148 |
class ReleaseAtEndOfTransaction |
4881 |
03 Jul 18 |
nicklas |
149 |
implements TransactionalAction |
4881 |
03 Jul 18 |
nicklas |
150 |
{ |
4881 |
03 Jul 18 |
nicklas |
151 |
private final I item; |
4881 |
03 Jul 18 |
nicklas |
152 |
private final boolean atCommit; |
4881 |
03 Jul 18 |
nicklas |
153 |
private final boolean atRollback; |
4881 |
03 Jul 18 |
nicklas |
154 |
|
4881 |
03 Jul 18 |
nicklas |
155 |
public ReleaseAtEndOfTransaction(I item, boolean atCommit, boolean atRollback) |
4881 |
03 Jul 18 |
nicklas |
156 |
{ |
4881 |
03 Jul 18 |
nicklas |
157 |
this.item = item; |
4881 |
03 Jul 18 |
nicklas |
158 |
this.atCommit = atCommit; |
4881 |
03 Jul 18 |
nicklas |
159 |
this.atRollback = atRollback; |
4881 |
03 Jul 18 |
nicklas |
160 |
} |
4881 |
03 Jul 18 |
nicklas |
161 |
|
4881 |
03 Jul 18 |
nicklas |
162 |
@Override |
4881 |
03 Jul 18 |
nicklas |
163 |
public void onBeforeCommit() |
4881 |
03 Jul 18 |
nicklas |
164 |
{} |
4881 |
03 Jul 18 |
nicklas |
165 |
@Override |
4881 |
03 Jul 18 |
nicklas |
166 |
public void onAfterCommit() |
4881 |
03 Jul 18 |
nicklas |
167 |
{ |
4881 |
03 Jul 18 |
nicklas |
168 |
if (atCommit) release(item); |
4881 |
03 Jul 18 |
nicklas |
169 |
} |
4881 |
03 Jul 18 |
nicklas |
170 |
@Override |
4881 |
03 Jul 18 |
nicklas |
171 |
public void onRollback() |
4881 |
03 Jul 18 |
nicklas |
172 |
{ |
4881 |
03 Jul 18 |
nicklas |
173 |
if (atRollback) release(item); |
4881 |
03 Jul 18 |
nicklas |
174 |
} |
4881 |
03 Jul 18 |
nicklas |
175 |
} |
2614 |
29 Aug 14 |
nicklas |
176 |
} |