View Javadoc
1   package locklib;
2   
3   import ensure.Ensure;
4   
5   /**
6    * <p>A lock grant represents the successful acquisition of a lock. Lock grants
7    * can be either <em>valid</em> or <em>invalid</em>. They are created
8    * valid but, once the lock is released, they become invalid (meaning the
9    * lock granted has been revoked).</p>
10   * 
11   * <p>Lock grants are organized in chains: the previous lock in a chain is
12   * called the <em>predecessor</em> lock and the next lock in the chain is
13   * called the <em>successor</em> lock. The first lock in the chain has no
14   * predecessor and the last has no successor. Chains are built from the
15   * target hierarchy: beginning of the chain is the top element in the
16   * target hierarchy and the last element in the lock chain is placed in the
17   * bottom element locked in target hierarchy.</p>
18   * 
19   * <p>When being acquired, predecessor locks must be acquired <em>before</em>
20   * and released <em>after</em>. This is handled transparently
21   * by <em>locklib</em>.</p>
22   * 
23   * <p>Lock grants are acquired through {@link LockGrantFuture}.</p>
24   * 
25   * <p>Synchronization locks on <code>LockGrant</code> should never be made
26   * outside <em>locklib</em></p>.
27   * @param <LockType> type of lock
28   */
29  /*
30   * Implementation notes:
31   * 
32   * LockGrants are self-contained from a synchronization perspective: they do
33   * not invoke any object of another class with a lock held.
34   * 
35   * LockGrants may need to acquire several synchronization locks on lock grants.
36   * The rule is that successors have to be locked before predecessors.
37   * 
38   * LockGrants must be acquired forward in the chain and released backwards.
39   * This means that LockGrants can only be acquired once the predecessor grant
40   * has been acquired and can only be released after their successor has been
41   * released.
42   * 
43   * LockGrants do not change anything else other than their own state. They do
44   * interact with other grants in the chain to ensure consistency.
45   */
46  public class LockGrant<LockType> {
47  	/**
48  	 * The lock requested.
49  	 */
50  	private LockRequest<LockType> m_request;
51  	
52  	/**
53  	 * The lock target.
54  	 */
55  	private Target<LockType> m_target;
56  	
57  	/**
58  	 * The predecessor lock that must be released <em>after</em> this one.
59  	 */
60  	private LockGrant<LockType> m_predecessor;
61  	
62  	/**
63  	 * The successor lock that must be released <em>before</em> this one.
64  	 */
65  	private LockGrant<LockType> m_successor;
66  	
67  	/**
68  	 * Is this grant still valid?
69  	 */
70  	private boolean m_valid;
71  	
72  	/**
73  	 * Creates a new grant.
74  	 * @param r the lock requested
75  	 * @param t the target where the lock has been granted
76  	 * @param predecessor an optional predecessor
77  	 */
78  	LockGrant(LockRequest<LockType> r, Target<LockType> t,
79  			LockGrant<LockType> predecessor) {
80  		Ensure.not_null(r, "r == null");
81  		Ensure.not_null(t, "t == null");
82  		
83  		m_request = r;
84  		m_target = t;
85  		m_predecessor = predecessor;
86  		m_valid = true;
87  		m_successor = null;
88  		
89  		/*
90  		 * Set this lock as the successor of the predecessor lock if there is
91  		 * a predecessor lock.
92  		 */
93  		if (predecessor != null) {
94  			synchronized (predecessor) {
95  				Ensure.is_null(predecessor.m_successor,
96  						"predecessor.m_successor != null");
97  				Ensure.is_true(predecessor.m_valid, "!predecessor.m_valid");
98  				predecessor.m_successor = this;
99  			}
100 		}
101 	}
102 	
103 	/**
104 	 * Checks whether this grant is still valid or not.
105 	 * @return is the grant still valid?
106 	 */
107 	public synchronized boolean valid() {
108 		return m_valid;
109 	}
110 	
111 	/**
112 	 * Invalidates a valid lock grant making it invalid.
113 	 */
114 	void invalidate() {
115 		LockGrant<LockType> suc;
116 		
117 		/*
118 		 * This is tricky but successors need to be held before predecessors.
119 		 * So first we must figure out if we have a successor to lock and check
120 		 * its state *before* locking and checking ourselves.
121 		 */
122 		synchronized (this) {
123 			suc = m_successor;
124 		}
125 		
126 		if (suc != null) {
127 			synchronized (m_successor) {
128 				Ensure.is_false(m_successor.m_valid, "m_successor.m_valid");
129 				synchronized (this) {
130 					Ensure.is_true(m_valid, "!m_valid");
131 					m_valid = false;
132 				}
133 			}
134 		} else {
135 			synchronized (this) {
136 				Ensure.is_true(m_valid, "!m_valid");
137 				m_valid = false;
138 			}
139 		}
140 	}
141 	
142 	/**
143 	 * Obtains the lock request that generated this grant.
144 	 * @return the request
145 	 */
146 	public synchronized LockRequest<LockType> request() {
147 		return m_request;
148 	}
149 	
150 	/**
151 	 * Obtains the locked target.
152 	 * @return the target
153 	 */
154 	public synchronized Target<LockType> target() {
155 		return m_target;
156 	}
157 	
158 	/**
159 	 * Obtains the predecessor grant, if any.
160 	 * @return the grant or <code>null</code> if there is none
161 	 */
162 	synchronized LockGrant<LockType> predecessor() {
163 		return m_predecessor;
164 	}
165 	
166 	/**
167 	 * Obtains the successor grant, if any.
168 	 * @return the grant or <code>null</code> if there is none
169 	 */
170 	synchronized LockGrant<LockType> successor() {
171 		return m_successor;
172 	}
173 	
174 	/**
175 	 * Releases the grant. This is equivalent to invoke the
176 	 * {@link Target#unlock(LockGrant)} method of this grant's target.
177 	 */
178 	public void release() {
179 		target().unlock(this);
180 	}
181 	
182 	@Override
183 	public String toString() {
184 		return "LockGrant[request=" + m_request + ", target=" + m_target
185 				+ ", predecessor=" + m_predecessor + "]";
186 	}
187 }