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.constructs.nonstop.concurrency;
18  
19  import net.sf.ehcache.concurrent.LockType;
20  import net.sf.ehcache.concurrent.Sync;
21  import net.sf.ehcache.config.TimeoutBehaviorConfiguration.TimeoutBehaviorType;
22  import net.sf.ehcache.constructs.nonstop.NonStopCacheException;
23  import net.sf.ehcache.constructs.nonstop.NonstopActiveDelegateHolder;
24  import net.sf.ehcache.constructs.nonstop.store.NonstopStore;
25  
26  /***
27   * Class implementing {@link Sync} and that can be executed without getting stuck.
28   *
29   * @author Abhishek Sanoujam
30   *
31   */
32  class NonstopSync implements Sync {
33  
34      private final NonstopStore nonstopStore;
35      // private final Sync delegateSync;
36      private final ExplicitLockingContextThreadLocal explicitLockingContextThreadLocal;
37      private final Object key;
38      private final NonstopActiveDelegateHolder nonstopActiveDelegateHolder;
39  
40      /***
41       * Constructor accepting the {@link NonstopStore} and the actual {@link Sync}
42       *
43       * @param nonstopStore
44       * @param nonstopActiveDelegateHolder
45       * @param key
46       * @param key2
47       */
48      public NonstopSync(NonstopStore nonstopStore, NonstopActiveDelegateHolder nonstopActiveDelegateHolder,
49              ExplicitLockingContextThreadLocal explicitLockingContextThreadLocal, Object key) {
50          this.nonstopStore = nonstopStore;
51          this.nonstopActiveDelegateHolder = nonstopActiveDelegateHolder;
52          this.explicitLockingContextThreadLocal = explicitLockingContextThreadLocal;
53          this.key = key;
54      }
55  
56      /***
57       * Return the key associated with this {@link Sync}
58       *
59       * @return the key associated with this {@link Sync}
60       */
61      public Object getKey() {
62          return key;
63      }
64  
65      /***
66       * {@inheritDoc}
67       */
68      public boolean isHeldByCurrentThread(final LockType type) {
69          return nonstopStore.executeClusterOperation(new ExplicitLockingClusterOperation<Boolean>() {
70  
71              public Boolean performClusterOperation() {
72                  return nonstopActiveDelegateHolder.getUnderlyingCacheLockProvider().getSyncForKey(key).isHeldByCurrentThread(type);
73              }
74  
75              public Boolean performClusterOperationTimedOut(final TimeoutBehaviorType configuredTimeoutBehavior) {
76                  throw new NonStopCacheException("isHeldByCurrentThread() timed out");
77              }
78          });
79      }
80  
81      /***
82       * {@inheritDoc}
83       */
84      public void lock(final LockType type) {
85          final ExplicitLockingContext appThreadLockContext = explicitLockingContextThreadLocal.getCurrentThreadLockContext();
86          nonstopStore.executeClusterOperation(new ExplicitLockingClusterOperation<Void>() {
87  
88              public Void performClusterOperation() {
89                  nonstopActiveDelegateHolder.getUnderlyingCacheLockProvider().getSyncForKey(key).lock(type);
90                  appThreadLockContext.lockAcquired(NonstopThreadUniqueIdProvider.getCurrentNonstopThreadUniqueId());
91                  return null;
92              }
93  
94              public Void performClusterOperationTimedOut(final TimeoutBehaviorType configuredTimeoutBehavior) {
95                  // throw exception for all behaviors
96                  throw new NonStopCacheException("lock() timed out");
97              }
98          });
99      }
100 
101     /***
102      * {@inheritDoc}
103      */
104     public boolean tryLock(final LockType type, final long msec) throws InterruptedException {
105         final ExplicitLockingContext appThreadLockContext = explicitLockingContextThreadLocal.getCurrentThreadLockContext();
106         return nonstopStore.executeClusterOperation(new ExplicitLockingClusterOperation<Boolean>() {
107 
108             public Boolean performClusterOperation() throws Exception {
109                 final boolean lockAcquired = nonstopActiveDelegateHolder.getUnderlyingCacheLockProvider().getSyncForKey(key)
110                         .tryLock(type, msec);
111                 if (lockAcquired) {
112                     appThreadLockContext.lockAcquired(NonstopThreadUniqueIdProvider.getCurrentNonstopThreadUniqueId());
113                 }
114                 return lockAcquired;
115             }
116 
117             public Boolean performClusterOperationTimedOut(final TimeoutBehaviorType configuredTimeoutBehavior) {
118                 // throw exception for all behaviors
119                 throw new NonStopCacheException("tryLock() timed out");
120             }
121         });
122     }
123 
124     /***
125      * {@inheritDoc}
126      */
127     public void unlock(final LockType type) {
128         final ExplicitLockingContext appThreadLockContext = explicitLockingContextThreadLocal.getCurrentThreadLockContext();
129         nonstopStore.executeClusterOperation(new ExplicitLockingClusterOperation<Void>() {
130 
131             public Void performClusterOperation() {
132                 try {
133                     if (appThreadLockContext.areLocksAcquiredByOtherThreads(NonstopThreadUniqueIdProvider.getCurrentNonstopThreadUniqueId())) {
134                         // some other thread has acquired locks other than this current nonstop thread
135                         // this means rejoin has happened, lock acquired by previous nonstop thread
136                         throw new InvalidLockStateAfterRejoinException();
137                     } else {
138                         nonstopActiveDelegateHolder.getUnderlyingCacheLockProvider().getSyncForKey(key).unlock(type);
139                     }
140                 } finally {
141                     // clean up the lock stack anyway
142                     appThreadLockContext.lockReleased();
143                 }
144                 return null;
145             }
146 
147             public Void performClusterOperationTimedOut(final TimeoutBehaviorType configuredTimeoutBehavior) {
148                 // always clean up lock stack for unlock even on timeouts
149                 appThreadLockContext.lockReleased();
150                 // throw exception for all behaviors
151                 throw new NonStopCacheException("unlock() timed out");
152             }
153         });
154     }
155 
156 }