--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.services.cache.CachedItem\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.services.cache;\r
+\r
+import org.apache.derby.iapi.services.cache.Cacheable;\r
+import org.apache.derby.iapi.services.cache.CacheableFactory;\r
+import org.apache.derby.iapi.services.cache.CacheManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.context.ContextService;\r
+\r
+/**\r
+ A generic class to represent the cache related infomation of a cached object (Cacheable).\r
+ <P><PRE>\r
+ The relationship between isValid and settingIdentity can be explain by the\r
+ following life cycle of a cached item.\r
+\r
+ Stage 1 2 3\r
+ ----------------------\r
+ isValid F T T \r
+ settingIdentity X T F\r
+\r
+ In Stage 1, the CachedItem is created but it is invalid and has an entry\r
+ that is just a holder object with no identity.\r
+\r
+ In Stage 2, the identity has been set and the item is being created or\r
+ being faulted into the cache.\r
+\r
+ In Stage 3, the item found in the CachedItem entry\r
+ </PRE> <P>\r
+ Remove is set if this item is being removed out of existance, not just\r
+ being evicted from the cache. When the last referece to it release it from\r
+ the cache, it will be removed.\r
+ <BR>\r
+ RecentlyUsed is set whenever this item is accessed (via a keep() call).\r
+ It is reset by the clockHand as it sweeps around the cache looking for\r
+ victims to evict.\r
+\r
+ <P>MT - must be MT-safe and work with cache manager. Every method that\r
+ access (set or get) instance variables is synchronized on the cached item\r
+ object. The following method waits so it should not be called by the cache\r
+ manager inside a sync block: clean(), waitFor(), create(), remove().\r
+ (RESOLVE: need to move these from the cache manager to here)\r
+\r
+ @see org.apache.derby.impl.services.cache\r
+ @see Cacheable\r
+*/\r
+final class CachedItem {\r
+ /*\r
+ ** Fields\r
+ */\r
+\r
+ private boolean valid_ = false;\r
+ private boolean removeRequested_ = false;\r
+ private boolean settingIdentity_ = false;\r
+ private boolean removeOk_ = false;\r
+ private boolean recentlyUsed_ = false;\r
+\r
+ /**\r
+ The current keep count on the entry.\r
+\r
+ <BR> MT - single thread required : synchronization provided by cache manager.\r
+\r
+ */\r
+ private int keepCount;\r
+\r
+ /**\r
+ The Cacheable object being represented.\r
+\r
+ <BR> Mutable - content dynamic\r
+ */\r
+ private Cacheable entry;\r
+ \r
+ /**\r
+ Create a CachedItem in the not valid state.\r
+ */\r
+ public CachedItem() {\r
+ }\r
+\r
+ /**\r
+ Keep the cached object after a search.\r
+\r
+ */\r
+ public void keepAfterSearch() {\r
+ keepCount++;\r
+ setUsed(true);\r
+ }\r
+\r
+ public void keepForCreate() {\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(!isKept());\r
+ SanityManager.ASSERT(!isValid());\r
+ }\r
+ keepCount = 1;\r
+ settingIdentity_ = true;\r
+ }\r
+\r
+ public void unkeepForCreate( )\r
+ {\r
+ settingIdentityComplete();\r
+ unkeep();\r
+ }\r
+\r
+ public void keepForClean() {\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(isValid());\r
+ }\r
+ keepCount++;\r
+ }\r
+\r
+\r
+\r
+ /**\r
+ Unkeep the cached object.\r
+\r
+ <P>MT - not synchronized, only modified single threaded by the cache manager\r
+\r
+ @return if the object is still kept after this call. \r
+ */\r
+ public synchronized boolean unkeep() {\r
+ boolean unkept = --keepCount == 0;\r
+\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(keepCount >= 0);\r
+ }\r
+ return (unkept && removeRequested_);\r
+ }\r
+\r
+ /**\r
+ Is the cached object kept?\r
+\r
+ <P>MT - not synchronized, only accessed single threaded by the cache manager\r
+ */\r
+ public final boolean isKept() {\r
+\r
+ return keepCount != 0;\r
+ }\r
+\r
+ /**\r
+ Clean the cached object\r
+\r
+ <P>MT - <BR>\r
+ The wait will not release the lock on the cache manager, so the\r
+ cache manager should not waitfor clean inside a sync block or\r
+ the whole cache will freeze\r
+\r
+ @param forRemove if true, get rid of the backend persistent store object\r
+ @exception StandardException error thrown while writing cacheable\r
+ object to disk\r
+ */\r
+ public void clean(boolean forRemove) throws StandardException\r
+ {\r
+ entry.clean(forRemove);\r
+ }\r
+\r
+ /**\r
+ Set the state of the to-be removed flag.\r
+ */\r
+ public synchronized void setRemoveState() {\r
+ removeRequested_ = true;\r
+ }\r
+\r
+ /**\r
+ Does the cached object have a valid identity.\r
+ */\r
+ public final synchronized boolean isValid() {\r
+ return valid_;\r
+ }\r
+\r
+ /**\r
+ Set the valid state of the cached object.\r
+ */\r
+ public synchronized void setValidState(boolean flag) {\r
+ valid_ = flag;\r
+ removeRequested_ = false;\r
+ removeOk_ = false;\r
+ recentlyUsed_ = flag;\r
+ }\r
+\r
+ /**\r
+ Get the cached object.\r
+ */\r
+ public Cacheable getEntry() {\r
+ return entry;\r
+ }\r
+\r
+ /**\r
+ Make entry (the Cacheable) take on a new identity.\r
+ */\r
+ public Cacheable takeOnIdentity(CacheManager cm, CacheableFactory holderFactory,\r
+ Object key, boolean forCreate, Object createParameter)\r
+ throws StandardException {\r
+\r
+ // tell the object it needs to create itself\r
+ Cacheable oldEntry = entry;\r
+ if (oldEntry == null)\r
+ oldEntry = holderFactory.newCacheable(cm);\r
+\r
+ if (forCreate) {\r
+ entry = oldEntry.createIdentity(key, createParameter);\r
+ } else {\r
+ entry = oldEntry.setIdentity(key);\r
+ }\r
+\r
+ if (entry != null) {\r
+ // item was found or created\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(entry.getIdentity().equals(key));\r
+ }\r
+\r
+ return entry;\r
+ }\r
+\r
+ entry = oldEntry;\r
+ return null;\r
+ }\r
+\r
+ public synchronized void settingIdentityComplete() {\r
+ // notify all waiters that this item has finished setting its identity,\r
+ // successfully or not.\r
+ settingIdentity_ = false;\r
+ notifyAll();\r
+ }\r
+\r
+ /**\r
+ Allow use of the cacheable entry. \r
+ */\r
+\r
+ public synchronized Cacheable use() throws StandardException {\r
+\r
+// while (settingIdentity_) {\r
+// try {\r
+// if (SanityManager.DEBUG) {\r
+// SanityManager.DEBUG("CacheTrace", \r
+// "trying to use a cached item that is taking on an identity");\r
+// }\r
+//\r
+// wait();\r
+//\r
+// } catch (InterruptedException ie) {\r
+// throw StandardException.interrupt(ie);\r
+// }\r
+// }\r
+\r
+ // see if the setting of this identity failed ...\r
+ if (!valid_) {\r
+ return null;\r
+ }\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ if (SanityManager.DEBUG_ON("CacheTrace"))\r
+ SanityManager.DEBUG(\r
+ "CacheTrace", "item keep count is " + keepCount);\r
+ }\r
+\r
+\r
+ return entry;\r
+ }\r
+\r
+ /**\r
+ */\r
+ public void remove(boolean removeNow) throws StandardException {\r
+\r
+ if (!removeNow) {\r
+\r
+ synchronized (this) {\r
+ while (!removeOk_) {\r
+ try {\r
+ wait();\r
+ } catch (InterruptedException ie) {\r
+ throw StandardException.interrupt(ie);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ \r
+ clean(true);\r
+ }\r
+\r
+ public synchronized void notifyRemover() {\r
+\r
+ if (SanityManager.DEBUG) {\r
+ SanityManager.ASSERT(removeRequested_);\r
+ SanityManager.ASSERT(isKept());\r
+ }\r
+\r
+ removeOk_ = true;\r
+ notifyAll();\r
+ }\r
+\r
+ /**\r
+ The clock hand has swept past this entry.\r
+ */\r
+ public synchronized void setUsed(boolean flag)\r
+ {\r
+ recentlyUsed_ = flag;\r
+ }\r
+\r
+ /**\r
+ Has the cached object been referenced (kept) since the last sweep of\r
+ the clock hand?\r
+ */\r
+ public synchronized boolean recentlyUsed() {\r
+ return recentlyUsed_;\r
+ }\r
+}\r
+\r
+ \r
+ \r