This project has retired. For details please refer to its Attic page.
DefaultFileLockManager xref
View Javadoc
1   package org.apache.archiva.common.filelock;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.time.StopWatch;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  import org.springframework.stereotype.Service;
26  
27  import java.io.File;
28  import java.io.FileNotFoundException;
29  import java.io.IOException;
30  import java.io.RandomAccessFile;
31  import java.nio.channels.ClosedChannelException;
32  import java.util.concurrent.ConcurrentHashMap;
33  import java.util.concurrent.ConcurrentMap;
34  
35  /**
36   * @author Olivier Lamy
37   * @since 2.0.0
38   */
39  @Service("fileLockManager#default")
40  public class DefaultFileLockManager
41      implements FileLockManager
42  {
43      // TODO currently we create lock for read and write!!
44      // the idea could be to store lock here with various clients read/write
45      // only read could be a more simple lock and acquire a write lock means waiting the end of all reading threads
46      private static final ConcurrentMap<File, Lock> lockFiles = new ConcurrentHashMap<File, Lock>( 64 );
47  
48      private boolean skipLocking = true;
49  
50      private Logger log = LoggerFactory.getLogger( getClass() );
51  
52      private int timeout = 0;
53  
54  
55      @Override
56      public Lock readFileLock( File file )
57          throws FileLockException, FileLockTimeoutException
58      {
59          if ( skipLocking )
60          {
61              return new Lock( file );
62  
63          }
64          StopWatch stopWatch = new StopWatch();
65          boolean acquired = false;
66          mkdirs( file.getParentFile() );
67  
68          Lock lock = null;
69  
70          stopWatch.start();
71  
72          while ( !acquired )
73          {
74  
75              if ( timeout > 0 )
76              {
77                  long delta = stopWatch.getTime();
78                  log.debug( "delta {}, timeout {}", delta, timeout );
79                  if ( delta > timeout )
80                  {
81                      log.warn( "Cannot acquire read lock within {} millis. Will skip the file: {}", timeout, file );
82                      // we could not get the lock within the timeout period, so  throw  FileLockTimeoutException
83                      throw new FileLockTimeoutException();
84                  }
85              }
86  
87              Lock current = lockFiles.get( file );
88  
89              if ( current != null )
90              {
91                  log.debug( "read lock file exist continue wait" );
92                  continue;
93              }
94  
95              try
96              {
97                  lock = new Lock( file, false );
98                  createNewFileQuietly( file );
99                  lock.openLock( false, timeout > 0 );
100                 acquired = true;
101             }
102             catch ( FileNotFoundException e )
103             {
104                 // can happen if an other thread has deleted the file
105                 // close RandomAccessFile!!!
106                 if ( lock != null )
107                 {
108                     closeQuietly( lock.getRandomAccessFile() );
109                 }
110                 log.debug( "read Lock skip: {} try to create file", e.getMessage() );
111                 createNewFileQuietly( file );
112             }
113             catch ( IOException e )
114             {
115                 throw new FileLockException( e.getMessage(), e );
116             }
117             catch ( IllegalStateException e )
118             {
119                 log.debug( "openLock {}:{}", e.getClass(), e.getMessage() );
120             }
121         }
122         Lock current = lockFiles.putIfAbsent( file, lock );
123         if ( current != null )
124         {
125             lock = current;
126         }
127         return lock;
128 
129     }
130 
131 
132     @Override
133     public Lock writeFileLock( File file )
134         throws FileLockException, FileLockTimeoutException
135     {
136         if ( skipLocking )
137         {
138             return new Lock( file );
139         }
140 
141         mkdirs( file.getParentFile() );
142 
143         StopWatch stopWatch = new StopWatch();
144         boolean acquired = false;
145 
146         Lock lock = null;
147 
148         stopWatch.start();
149 
150         while ( !acquired )
151         {
152 
153             if ( timeout > 0 )
154             {
155                 long delta = stopWatch.getTime();
156                 log.debug( "delta {}, timeout {}", delta, timeout );
157                 if ( delta > timeout )
158                 {
159                     log.warn( "Cannot acquire read lock within {} millis. Will skip the file: {}", timeout, file );
160                     // we could not get the lock within the timeout period, so throw FileLockTimeoutException
161                     throw new FileLockTimeoutException();
162                 }
163             }
164 
165             Lock current = lockFiles.get( file );
166 
167             try
168             {
169 
170                 if ( current != null )
171                 {
172                     log.debug( "write lock file exist continue wait" );
173 
174                     continue;
175                 }
176                 lock = new Lock( file, true );
177                 createNewFileQuietly( file );
178                 lock.openLock( true, timeout > 0 );
179                 acquired = true;
180             }
181             catch ( FileNotFoundException e )
182             {
183                 // can happen if an other thread has deleted the file
184                 // close RandomAccessFile!!!
185                 if ( lock != null )
186                 {
187                     closeQuietly( lock.getRandomAccessFile() );
188                 }
189                 log.debug( "write Lock skip: {} try to create file", e.getMessage() );
190                 createNewFileQuietly( file );
191             }
192             catch ( IOException e )
193             {
194                 throw new FileLockException( e.getMessage(), e );
195             }
196             catch ( IllegalStateException e )
197             {
198                 log.debug( "openLock {}:{}", e.getClass(), e.getMessage() );
199             }
200         }
201 
202         Lock current = lockFiles.putIfAbsent( file, lock );
203         if ( current != null )
204         {
205             lock = current;
206         }
207 
208         return lock;
209 
210 
211     }
212 
213     private void closeQuietly( RandomAccessFile randomAccessFile )
214     {
215         if ( randomAccessFile == null )
216         {
217             return;
218         }
219 
220         try
221         {
222             randomAccessFile.close();
223         }
224         catch ( IOException e )
225         {
226             // ignore
227         }
228     }
229 
230     private void createNewFileQuietly( File file )
231     {
232         try
233         {
234             file.createNewFile();
235         }
236         catch ( IOException e )
237         {
238             // skip that
239         }
240     }
241 
242     @Override
243     public void release( Lock lock )
244         throws FileLockException
245     {
246         if ( lock == null )
247         {
248             log.debug( "skip releasing null" );
249             return;
250         }
251         if ( skipLocking )
252         {
253             return;
254         }
255         try
256         {
257             lockFiles.remove( lock.getFile() );
258             lock.close();
259         }
260         catch ( ClosedChannelException e )
261         {
262             // skip this one
263             log.debug( "ignore ClosedChannelException: {}", e.getMessage() );
264         }
265         catch ( IOException e )
266         {
267             throw new FileLockException( e.getMessage(), e );
268         }
269     }
270 
271     @Override
272     public void clearLockFiles()
273     {
274         lockFiles.clear();
275     }
276 
277     private boolean mkdirs( File directory )
278     {
279         return directory.mkdirs();
280     }
281 
282     @Override
283     public int getTimeout()
284     {
285         return timeout;
286     }
287 
288     @Override
289     public void setTimeout( int timeout )
290     {
291         this.timeout = timeout;
292     }
293 
294     @Override
295     public boolean isSkipLocking()
296     {
297         return skipLocking;
298     }
299 
300     @Override
301     public void setSkipLocking( boolean skipLocking )
302     {
303         this.skipLocking = skipLocking;
304     }
305 }