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  package net.sf.ehcache.pool.impl;
18  
19  import java.util.concurrent.locks.Lock;
20  import java.util.concurrent.locks.ReentrantLock;
21  
22  import net.sf.ehcache.pool.Pool;
23  import net.sf.ehcache.pool.PoolableStore;
24  import net.sf.ehcache.pool.Role;
25  import net.sf.ehcache.pool.SizeOfEngine;
26  
27  /***
28   * The PoolAccessor class of the StrictlyBoundedPool
29   *
30   * @author Ludovic Orban
31   */
32  final class LockedPoolAccessor extends AbstractPoolAccessor<PoolableStore> {
33  
34      private final SizeOfEngine sizeOfEngine;
35      private long size;
36      private final Lock lock = new ReentrantLock();
37  
38      /***
39       * Creates a locked pool accessor with the specified properties.
40       *
41       * @param pool pool to be accessed
42       * @param store accessing store
43       * @param sizeOfEngine engine used to size objects
44       * @param currentSize initial size of the store
45       */
46      LockedPoolAccessor(Pool pool, PoolableStore store, SizeOfEngine sizeOfEngine, long currentSize) {
47          super(pool, store);
48          this.sizeOfEngine = sizeOfEngine;
49          this.size = currentSize;
50      }
51  
52      /***
53       * {@inheritDoc}
54       */
55      public long add(Object key, Object value, Object container, boolean force) {
56          checkLinked();
57  
58          long sizeOf = sizeOfEngine.sizeOf(key, value, container);
59  
60          // synchronized makes the size update MT-safe but slow
61          lock.lock();
62          try {
63              while (true) {
64                  long newSize = getPool().getSize() + sizeOf;
65  
66                  if (newSize <= getPool().getMaxSize()) {
67                      // there is enough room => add & approve
68                      size += sizeOf;
69                      return sizeOf;
70                  } else {
71                      // check that the element isn't too big
72                      if (!force && sizeOf > getPool().getMaxSize()) {
73                          // this is too big to fit in the pool
74                          return -1;
75                      }
76  
77                      // if there is not enough room => evict
78                      long missingSize = newSize - getPool().getMaxSize();
79  
80                      // eviction must be done outside the lock to avoid deadlocks as it may evict from other pools
81                      lock.unlock();
82                      try {
83                          boolean successful = getPool().getEvictor().freeSpace(getPool().getPoolableStores(), missingSize);
84                          if (!force && !successful) {
85                              // cannot free enough bytes
86                              return -1;
87                          }
88                      } finally {
89                          lock.lock();
90                      }
91  
92                      // check that the freed space was not 'stolen' by another thread while
93                      // eviction was running out of the lock
94                      if (!force && getPool().getSize() + sizeOf > getPool().getMaxSize()) {
95                          continue;
96                      }
97  
98                      size += sizeOf;
99                      return sizeOf;
100                 }
101             }
102         } finally {
103             lock.unlock();
104         }
105     }
106 
107     /***
108      * {@inheritDoc}
109      */
110     public boolean canAddWithoutEvicting(Object key, Object value, Object container) {
111         long sizeOf = sizeOfEngine.sizeOf(key, value, container);
112 
113         lock.lock();
114         try {
115             long newSize = getPool().getSize() + sizeOf;
116             return newSize <= getPool().getMaxSize();
117         } finally {
118             lock.unlock();
119         }
120     }
121 
122     /***
123      * {@inheritDoc}
124      */
125     public long delete(Object key, Object value, Object container) {
126         checkLinked();
127 
128         long sizeOf = sizeOfEngine.sizeOf(key, value, container);
129 
130         // synchronized makes the size update MT-safe but slow
131         lock.lock();
132         try {
133             size -= sizeOf;
134         } finally {
135             lock.unlock();
136         }
137 
138         return sizeOf;
139     }
140 
141     /***
142      * {@inheritDoc}
143      */
144     @Override
145     public long replace(Role role, Object current, Object replacement, boolean force) {
146         // locking makes the size update MT-safe but slow
147         lock.lock();
148         try {
149             return super.replace(role, current, replacement, force);
150         } finally {
151             lock.unlock();
152         }
153     }
154 
155     /***
156      * {@inheritDoc}
157      */
158     public long getSize() {
159         // locking makes the size update MT-safe but slow
160         lock.lock();
161         try {
162             return size;
163         } finally {
164             lock.unlock();
165         }
166     }
167 
168     /***
169      * {@inheritDoc}
170      */
171     public void clear() {
172         // locking makes the size update MT-safe but slow
173         lock.lock();
174         try {
175             size = 0L;
176         } finally {
177             lock.unlock();
178         }
179     }
180 }