1 /***
2 * Copyright 2003-2010 Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /***
18 *
19 */
20 package net.sf.ehcache.store.disk;
21
22 import net.sf.ehcache.pool.sizeof.annotations.IgnoreSizeOf;
23 import net.sf.ehcache.util.VmUtils;
24
25 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
26
27 /***
28 * Internal entry structure used by the {@link net.sf.ehcache.store.disk.Segment} class.
29 *
30 * @author Chris Dennis
31 * @author Ludovic Orban
32 */
33 public abstract class HashEntry {
34
35 /***
36 * Key instance for this mapping.
37 */
38 @IgnoreSizeOf
39 protected final Object key;
40
41 /***
42 * Spread hash value for they key.
43 */
44 protected final int hash;
45
46 /***
47 * Reference to the next HashEntry in this chain.
48 */
49 @IgnoreSizeOf
50 protected final HashEntry next;
51
52
53 /***
54 * Constructs a HashEntry instance mapping the supplied key, value pair
55 * and linking it to the supplied HashEntry
56 *
57 * @param key key for this entry
58 * @param hash spread-hash for this entry
59 * @param next next HashEntry in the chain
60 * @param element initial value for this entry
61 */
62 private HashEntry(Object key, int hash, HashEntry next, Object element) {
63 this.key = key;
64 this.hash = hash;
65 this.next = next;
66
67 setElement(element);
68 }
69
70 /***
71 * Create a new HashEntry instance
72 *
73 * @param key the key
74 * @param hash the hash of the key
75 * @param next the next hashEntry
76 * @param element the element
77 * @return a new HashEntry instance
78 */
79 static HashEntry newHashEntry(Object key, int hash, HashEntry next, Object element) {
80 if (VmUtils.isInGoogleAppEngine()) {
81 return new SynchronizedHashEntry(key, hash, next, element);
82 }
83 return new AtomicHashEntry(key, hash, next, element);
84 }
85
86 /***
87 * Volatile read of this entry's element reference.
88 *
89 * @return mapped element
90 */
91 abstract Object getElement();
92
93 /***
94 * Volatile write of this entry's element reference.
95 *
96 * @param element to map
97 */
98 abstract void setElement(Object element);
99
100 /***
101 * Atomic compare-and-swap of this entry's element reference.
102 *
103 * @param expect expected value
104 * @param update value to install
105 * @return <code>true</code> if the CAS succeeded
106 */
107 abstract boolean casElement(Object expect, Object update);
108
109 /***
110 * Atomic get-and-set of this entry's element reference.
111 *
112 * @param element value to install
113 * @return previous value
114 */
115 abstract Object gasElement(Object element);
116
117 /***
118 *
119 */
120 static class AtomicHashEntry extends HashEntry {
121
122 /***
123 * Field updater used to atomically update the volatile Element reference.
124 */
125 private static final AtomicReferenceFieldUpdater<AtomicHashEntry, Object> ELEMENT_UPDATER =
126 AtomicReferenceFieldUpdater.newUpdater(AtomicHashEntry.class, Object.class, "element");
127
128 /***
129 * Volatile reference to the current value (or substitute value) for this mapping
130 */
131 @IgnoreSizeOf
132 private volatile Object element;
133
134
135 /***
136 * Constructs a AtomicHashEntry instance mapping the supplied key, value pair
137 * and linking it to the supplied HashEntry
138 *
139 * @param key key for this entry
140 * @param hash spread-hash for this entry
141 * @param next next HashEntry in the chain
142 * @param element initial value for this entry
143 */
144 AtomicHashEntry(Object key, int hash, HashEntry next, Object element) {
145 super(key, hash, next, element);
146 }
147
148 /***
149 * Volatile read of this entry's element reference.
150 *
151 * @return mapped element
152 */
153 Object getElement() {
154 return ELEMENT_UPDATER.get(this);
155 }
156
157 /***
158 * Volatile write of this entry's element reference.
159 *
160 * @param element to map
161 */
162 void setElement(Object element) {
163 ELEMENT_UPDATER.set(this, element);
164 }
165
166 /***
167 * Atomic compare-and-swap of this entry's element reference.
168 *
169 * @param expect expected value
170 * @param update value to install
171 * @return <code>true</code> if the CAS succeeded
172 */
173 boolean casElement(Object expect, Object update) {
174 return ELEMENT_UPDATER.compareAndSet(this, expect, update);
175 }
176
177 /***
178 * Atomic get-and-set of this entry's element reference.
179 *
180 * @param element value to install
181 * @return previous value
182 */
183 Object gasElement(Object element) {
184 return ELEMENT_UPDATER.getAndSet(this, element);
185 }
186 }
187
188 /***
189 *
190 */
191 static class SynchronizedHashEntry extends HashEntry {
192
193 /***
194 * Volatile reference to the current value (or substitute value) for this mapping
195 */
196 @IgnoreSizeOf
197 private volatile Object element;
198
199 /***
200 * Constructs a AtomicHashEntry instance mapping the supplied key, value pair
201 * and linking it to the supplied AtomicHashEntry
202 *
203 * @param key key for this entry
204 * @param hash spread-hash for this entry
205 * @param next next AtomicHashEntry in the chain
206 * @param element initial value for this entry
207 */
208 SynchronizedHashEntry(Object key, int hash, HashEntry next, Object element) {
209 super(key, hash, next, element);
210 }
211
212 /***
213 * Volatile read of this entry's element reference.
214 *
215 * @return mapped element
216 */
217 synchronized Object getElement() {
218 return element;
219 }
220
221 /***
222 * Volatile write of this entry's element reference.
223 *
224 * @param element to map
225 */
226 synchronized void setElement(Object element) {
227 this.element = element;
228 }
229
230 /***
231 * Atomic compare-and-swap of this entry's element reference.
232 *
233 * @param expect expected value
234 * @param update value to install
235 * @return <code>true</code> if the CAS succeeded
236 */
237 synchronized boolean casElement(Object expect, Object update) {
238 if (this.element == expect) {
239 this.element = update;
240 return true;
241 }
242 return false;
243 }
244
245 /***
246 * Atomic get-and-set of this entry's element reference.
247 *
248 * @param element value to install
249 * @return previous value
250 */
251 synchronized Object gasElement(Object element) {
252 Object oldElement = this.element;
253 this.element = element;
254 return oldElement;
255 }
256 }
257
258 }