Source code: org/apache/derby/impl/services/cache/CachedItem.java
1 /*
2
3 Derby - Class org.apache.derby.impl.services.cache.CachedItem
4
5 Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11 http://www.apache.org/licenses/LICENSE-2.0
12
13 Unless required by applicable law or agreed to in writing, software
14 distributed under the License is distributed on an "AS IS" BASIS,
15 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 See the License for the specific language governing permissions and
17 limitations under the License.
18
19 */
20
21 package org.apache.derby.impl.services.cache;
22
23 import org.apache.derby.iapi.services.cache.Cacheable;
24 import org.apache.derby.iapi.services.cache.CacheableFactory;
25 import org.apache.derby.iapi.services.cache.CacheManager;
26 import org.apache.derby.iapi.error.StandardException;
27
28 import org.apache.derby.iapi.services.sanity.SanityManager;
29 import org.apache.derby.iapi.services.context.ContextService;
30
31 /**
32 A generic class to represent the cache related infomation of a cached object (Cacheable).
33 <P><PRE>
34 The relationship between isValid and settingIdentity can be explain by the
35 following life cycle of a cached item.
36
37 Stage 1 2 3
38 ----------------------
39 isValid F T T
40 settingIdentity X T F
41
42 In Stage 1, the CachedItem is created but it is invalid and has an entry
43 that is just a holder object with no identity.
44
45 In Stage 2, the identity has been set and the item is being created or
46 being faulted into the cache.
47
48 In Stage 3, the item found in the CachedItem entry
49 </PRE> <P>
50 Remove is set if this item is being removed out of existance, not just
51 being evicted from the cache. When the last referece to it release it from
52 the cache, it will be removed.
53 <BR>
54 RecentlyUsed is set whenever this item is accessed (via a keep() call).
55 It is reset by the clockHand as it sweeps around the cache looking for
56 victims to evict.
57
58 <P>MT - must be MT-safe and work with cache manager. Every method that
59 access (set or get) instance variables is synchronized on the cached item
60 object. The following method waits so it should not be called by the cache
61 manager inside a sync block: clean(), waitFor(), create(), remove().
62 (RESOLVE: need to move these from the cache manager to here)
63
64 @see org.apache.derby.impl.services.cache
65 @see Cacheable
66 */
67 public final class CachedItem {
68
69 private static final int VALID = 0x00000001;
70 private static final int REMOVE_REQUESTED = 0x00000002;
71 private static final int SETTING_IDENTITY = 0x00000004;
72 private static final int REMOVE_OK = 0x00000008;
73
74 private static final int RECENTLY_USED = 0x00000010;
75
76 /*
77 ** Fields
78 */
79
80 /**
81 Does entry (the Cacheable) have an identity.
82
83 <BR> MT - single thread required : synchronization provided by cache manager.
84 */
85 private int state;
86
87 /**
88 The current keep count on the entry.
89
90 <BR> MT - single thread required : synchronization provided by cache manager.
91
92 */
93 private int keepCount;
94
95 /**
96 The Cacheable object being represented.
97
98 <BR> Mutable - content dynamic
99 */
100 private Cacheable entry;
101
102 /**
103 Create a CachedItem in the not valid state.
104 */
105 public CachedItem() {
106 }
107
108 /**
109 Keep the cached object after a search.
110
111 */
112 public void keepAfterSearch() {
113 keepCount++;
114 setUsed(true);
115 }
116
117 public void keepForCreate() {
118 if (SanityManager.DEBUG) {
119 SanityManager.ASSERT(!isKept());
120 SanityManager.ASSERT(!isValid());
121 }
122 keepCount = 1;
123 state |= SETTING_IDENTITY;
124 }
125
126 public void unkeepForCreate( )
127 {
128 settingIdentityComplete();
129 unkeep();
130 }
131
132 public void keepForClean() {
133 if (SanityManager.DEBUG) {
134 SanityManager.ASSERT(isValid());
135 }
136 keepCount++;
137 }
138
139
140
141 /**
142 Unkeep the cached object.
143
144 <P>MT - not synchronized, only modified single threaded by the cache manager
145
146 @return if the object is still kept after this call.
147 */
148 public synchronized boolean unkeep() {
149 boolean unkept = --keepCount == 0;
150
151 if (SanityManager.DEBUG) {
152 SanityManager.ASSERT(keepCount >= 0);
153 }
154 return unkept && ((state & REMOVE_REQUESTED) != 0);
155 }
156
157 /**
158 Is the cached object kept?
159
160 <P>MT - not synchronized, only accessed single threaded by the cache manager
161 */
162 public final boolean isKept() {
163
164 return keepCount != 0;
165 }
166
167 /**
168 Clean the cached object
169
170 <P>MT - <BR>
171 The wait will not release the lock on the cache manager, so the
172 cache manager should not waitfor clean inside a sync block or
173 the whole cache will freeze
174
175 @param forRemove if true, get rid of the backend persistent store object
176 @exception StandardException error thrown while writing cacheable
177 object to disk
178 */
179 public void clean(boolean forRemove) throws StandardException
180 {
181 entry.clean(forRemove);
182 }
183
184 /**
185 Set the state of the to-be removed flag.
186 */
187 public synchronized void setRemoveState() {
188 state |= REMOVE_REQUESTED;
189 }
190
191 /**
192 Does the cached object have a valid identity.
193 */
194 public final synchronized boolean isValid() {
195 return (state & VALID) != 0;
196 }
197
198 /**
199 Set the valid state of the cached object.
200 */
201 public synchronized void setValidState(boolean flag) {
202
203 if (flag)
204 state |= VALID;
205 else
206 state &= ~VALID;
207
208 state &= ~(REMOVE_REQUESTED | REMOVE_OK);
209
210 setUsed(flag);
211 }
212
213 /**
214 Get the cached object.
215 */
216 public Cacheable getEntry() {
217 return entry;
218 }
219
220 /**
221 Make entry (the Cacheable) take on a new identity.
222 */
223 public Cacheable takeOnIdentity(CacheManager cm, CacheableFactory holderFactory,
224 Object key, boolean forCreate, Object createParameter)
225 throws StandardException {
226
227 // tell the object it needs to create itself
228 Cacheable oldEntry = entry;
229 if (oldEntry == null)
230 oldEntry = holderFactory.newCacheable(cm);
231
232 if (forCreate) {
233 entry = oldEntry.createIdentity(key, createParameter);
234 } else {
235 entry = oldEntry.setIdentity(key);
236 }
237
238 if (entry != null) {
239 // item was found or created
240 if (SanityManager.DEBUG) {
241 SanityManager.ASSERT(entry.getIdentity().equals(key));
242 }
243
244 return entry;
245 }
246
247 entry = oldEntry;
248 return null;
249 }
250
251 public synchronized void settingIdentityComplete() {
252 // notify all waiters that this item has finished setting its identity,
253 // successfully or not.
254 state &= ~SETTING_IDENTITY;
255
256 notifyAll();
257 }
258
259 /**
260 Allow use of the cacheable entry.
261 */
262
263 public synchronized Cacheable use() throws StandardException {
264
265 while ((state & SETTING_IDENTITY) != 0) {
266 try {
267 if (SanityManager.DEBUG) {
268 SanityManager.DEBUG("CacheTrace",
269 "trying to use a cached item that is taking on an identity");
270 }
271
272 wait();
273
274 } catch (InterruptedException ie) {
275 throw StandardException.interrupt(ie);
276 }
277 }
278
279 // see if the setting of this identity failed ...
280 if (!isValid())
281 return null;
282
283 if (SanityManager.DEBUG)
284 {
285 if (SanityManager.DEBUG_ON("CacheTrace"))
286 SanityManager.DEBUG(
287 "CacheTrace", "item keep count is " + keepCount);
288 }
289
290
291 return entry;
292 }
293
294 /**
295 */
296 public void remove(boolean removeNow) throws StandardException {
297
298 if (!removeNow) {
299
300 synchronized (this) {
301 while ((state & REMOVE_OK) == 0) {
302 try {
303 wait();
304 } catch (InterruptedException ie) {
305 throw StandardException.interrupt(ie);
306 }
307 }
308 }
309 }
310
311 clean(true);
312 }
313
314 public synchronized void notifyRemover() {
315
316 if (SanityManager.DEBUG) {
317 SanityManager.ASSERT((state & REMOVE_REQUESTED) != 0);
318 SanityManager.ASSERT(isKept());
319 }
320
321 state |= REMOVE_OK;
322 notifyAll();
323 }
324
325 /**
326 The clock hand has swept past this entry.
327 */
328 public synchronized void setUsed(boolean flag)
329 {
330 if (flag)
331 state |= RECENTLY_USED;
332 else
333 state &= ~RECENTLY_USED;
334 }
335
336 /**
337 Has the cached object been referenced (kept) since the last sweep of
338 the clock hand?
339 */
340 public synchronized boolean recentlyUsed() {
341 return (state & RECENTLY_USED) != 0;
342 }
343 }
344
345
346