001: /*
002: * Copyright (c) 2002-2003 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.oscache.base;
006:
007: /**
008: * Holds the state of a Cache Entry that is in the process of being (re)generated.
009: * This is not synchronized; the synchronization must be handled by the calling
010: * classes.
011: *
012: * @author <a href="mailto:chris@swebtec.com">Chris Miller</a>
013: * @author Author: $
014: * @version Revision: $
015: */
016: public class EntryUpdateState {
017: /**
018: * The initial state when this object is first created
019: */
020: public static final int NOT_YET_UPDATING = -1;
021:
022: /**
023: * Update in progress state
024: */
025: public static final int UPDATE_IN_PROGRESS = 0;
026:
027: /**
028: * Update complete state
029: */
030: public static final int UPDATE_COMPLETE = 1;
031:
032: /**
033: * Update cancelled state
034: */
035: public static final int UPDATE_CANCELLED = 2;
036:
037: /**
038: * Current update state
039: */
040: int state = NOT_YET_UPDATING;
041:
042: /**
043: * A counter of the number of threads that are coordinated through this instance. When this counter gets to zero, then the reference to this
044: * instance may be released from the Cache instance.
045: * This is counter is protected by the EntryStateUpdate instance monitor.
046: */
047: private int nbConcurrentUses = 1;
048:
049: /**
050: * This is the initial state when an instance this object is first created.
051: * It indicates that a cache entry needs updating, but no thread has claimed
052: * responsibility for updating it yet.
053: */
054: public boolean isAwaitingUpdate() {
055: return state == NOT_YET_UPDATING;
056: }
057:
058: /**
059: * The thread that was responsible for updating the cache entry (ie, the thread
060: * that managed to grab the update lock) has decided to give up responsibility
061: * for performing the update. OSCache will notify any other threads that are
062: * waiting on the update so one of them can take over the responsibility.
063: */
064: public boolean isCancelled() {
065: return state == UPDATE_CANCELLED;
066: }
067:
068: /**
069: * The update of the cache entry has been completed.
070: */
071: public boolean isComplete() {
072: return state == UPDATE_COMPLETE;
073: }
074:
075: /**
076: * The cache entry is currently being generated by the thread that got hold of
077: * the update lock.
078: */
079: public boolean isUpdating() {
080: return state == UPDATE_IN_PROGRESS;
081: }
082:
083: /**
084: * Updates the state to <code>UPDATE_CANCELLED</code>. This should <em>only<em>
085: * be called by the thread that managed to get the update lock.
086: * @return the counter value after the operation completed
087: */
088: public int cancelUpdate() {
089: if (state != UPDATE_IN_PROGRESS) {
090: throw new IllegalStateException(
091: "Cannot cancel cache update - current state ("
092: + state + ") is not UPDATE_IN_PROGRESS");
093: }
094:
095: state = UPDATE_CANCELLED;
096: return decrementUsageCounter();
097: }
098:
099: /**
100: * Updates the state to <code>UPDATE_COMPLETE</code>. This should <em>only</em>
101: * be called by the thread that managed to get the update lock.
102: * @return the counter value after the operation completed
103: */
104: public int completeUpdate() {
105: if (state != UPDATE_IN_PROGRESS) {
106: throw new IllegalStateException(
107: "Cannot complete cache update - current state ("
108: + state + ") is not UPDATE_IN_PROGRESS");
109: }
110:
111: state = UPDATE_COMPLETE;
112: return decrementUsageCounter();
113: }
114:
115: /**
116: * Attempt to change the state to <code>UPDATE_IN_PROGRESS</code>. Calls
117: * to this method must be synchronized on the EntryUpdateState instance.
118: * @return the counter value after the operation completed
119: */
120: public int startUpdate() {
121: if ((state != NOT_YET_UPDATING) && (state != UPDATE_CANCELLED)) {
122: throw new IllegalStateException(
123: "Cannot begin cache update - current state ("
124: + state
125: + ") is not NOT_YET_UPDATING or UPDATE_CANCELLED");
126: }
127:
128: state = UPDATE_IN_PROGRESS;
129: return incrementUsageCounter();
130: }
131:
132: /**
133: * Increments the usage counter by one
134: * @return the counter value after the increment
135: */
136: public synchronized int incrementUsageCounter() {
137: nbConcurrentUses++;
138: return nbConcurrentUses;
139: }
140:
141: /**
142: * Gets the current usage counter value
143: * @return a positive number.
144: */
145: public synchronized int getUsageCounter() {
146: return nbConcurrentUses;
147: }
148:
149: /**
150: * Decrements the usage counter by one. This method may only be called when the usage number is greater than zero
151: * @return the counter value after the decrement
152: */
153: public synchronized int decrementUsageCounter() {
154: if (nbConcurrentUses <= 0) {
155: throw new IllegalStateException(
156: "Cannot decrement usage counter, it is already equals to ["
157: + nbConcurrentUses + "]");
158: }
159: nbConcurrentUses--;
160: return nbConcurrentUses;
161: }
162:
163: }
|