View Javadoc

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 }