]> source.dussan.org Git - archiva.git/blob
09008e2a72d5141e8811265f12d5803755c85955
[archiva.git] /
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.util.concurrent.ConcurrentHashMap;
32 import java.util.concurrent.ConcurrentMap;
33
34 /**
35  * @author Olivier Lamy
36  * @since 2.0.0
37  */
38 @Service( "fileLockManager#default" )
39 public class DefaultFileLockManager
40     implements FileLockManager
41 {
42     // TODO currently we create lock for read and write!!
43     // the idea could be to store lock here with various clients read/write
44     // only read could be a more simple lock and acquire a write lock means waiting the end of all reading threads
45     private static final ConcurrentMap<File, Lock> lockFiles = new ConcurrentHashMap<File, Lock>( 64 );
46
47     private boolean skipLocking = true;
48
49     private Logger log = LoggerFactory.getLogger( getClass() );
50
51     private int timeout = 0;
52
53
54     @Override
55     public Lock readFileLock( File file )
56         throws FileLockException, FileLockTimeoutException
57     {
58         if ( skipLocking )
59         {
60             return new Lock( file );
61
62         }
63         StopWatch stopWatch = new StopWatch();
64         boolean acquired = false;
65         mkdirs( file.getParentFile() );
66
67         Lock lock = null;
68
69         stopWatch.start();
70
71         while ( !acquired )
72         {
73
74             if ( timeout > 0 )
75             {
76                 long delta = stopWatch.getTime();
77                 log.debug( "delta {}, timeout {}", delta, timeout );
78                 if ( delta > timeout )
79                 {
80                     log.warn( "Cannot acquire read lock within {} millis. Will skip the file: {}", timeout, file );
81                     // we could not get the lock within the timeout period, so  throw  FileLockTimeoutException
82                     throw new FileLockTimeoutException();
83                 }
84             }
85
86             Lock current = lockFiles.get( file );
87
88             if ( current != null )
89             {
90                 log.debug( "read lock file exist continue wait" );
91                 continue;
92             }
93
94             try
95             {
96                 lock = new Lock( file, false );
97                 createNewFileQuietly( file );
98                 lock.openLock( false, timeout > 0 );
99                 acquired = true;
100             }
101             catch ( FileNotFoundException e )
102             {
103                 // can happen if an other thread has deleted the file
104                 // close RandomAccessFile!!!
105                 if ( lock != null )
106                 {
107                     closeQuietly( lock.getRandomAccessFile() );
108                 }
109                 log.debug( "read Lock skip: {} try to create file", e.getMessage() );
110                 createNewFileQuietly( file );
111             }
112             catch ( IOException e )
113             {
114                 throw new FileLockException( e.getMessage(), e );
115             }
116             catch ( IllegalStateException e )
117             {
118                 log.debug( "openLock {}:{}", e.getClass(), e.getMessage() );
119             }
120         }
121         Lock current = lockFiles.putIfAbsent( file, lock );
122         if ( current != null )
123         {
124             lock = current;
125         }
126         return lock;
127
128     }
129
130
131     @Override
132     public Lock writeFileLock( File file )
133         throws FileLockException, FileLockTimeoutException
134     {
135         if ( skipLocking )
136         {
137             return new Lock( file );
138         }
139
140         mkdirs( file.getParentFile() );
141
142         StopWatch stopWatch = new StopWatch();
143         boolean acquired = false;
144
145         Lock lock = null;
146
147         stopWatch.start();
148
149         while ( !acquired )
150         {
151
152             if ( timeout > 0 )
153             {
154                 long delta = stopWatch.getTime();
155                 log.debug( "delta {}, timeout {}", delta, timeout );
156                 if ( delta > timeout )
157                 {
158                     log.warn( "Cannot acquire read lock within {} millis. Will skip the file: {}", timeout, file );
159                     // we could not get the lock within the timeout period, so throw FileLockTimeoutException
160                     throw new FileLockTimeoutException();
161                 }
162             }
163
164             Lock current = lockFiles.get( file );
165
166             try
167             {
168
169                 if ( current != null )
170                 {
171                     log.debug( "write lock file exist continue wait" );
172
173                     continue;
174                 }
175                 lock = new Lock( file, true );
176                 createNewFileQuietly( file );
177                 lock.openLock( true, timeout > 0 );
178                 acquired = true;
179             }
180             catch ( FileNotFoundException e )
181             {
182                 // can happen if an other thread has deleted the file
183                 // close RandomAccessFile!!!
184                 if ( lock != null )
185                 {
186                     closeQuietly( lock.getRandomAccessFile() );
187                 }
188                 log.debug( "write Lock skip: {} try to create file", e.getMessage() );
189                 createNewFileQuietly( file );
190             }
191             catch ( IOException e )
192             {
193                 throw new FileLockException( e.getMessage(), e );
194             }
195             catch ( IllegalStateException e )
196             {
197                 log.debug( "openLock {}:{}", e.getClass(), e.getMessage() );
198             }
199         }
200
201         Lock current = lockFiles.putIfAbsent( file, lock );
202         if ( current != null )
203         {
204             lock = current;
205         }
206
207         return lock;
208
209
210     }
211
212     private void closeQuietly( RandomAccessFile randomAccessFile )
213     {
214         if ( randomAccessFile == null )
215         {
216             return;
217         }
218
219         try
220         {
221             randomAccessFile.close();
222         }
223         catch ( IOException e )
224         {
225             // ignore
226         }
227     }
228
229     private void createNewFileQuietly( File file )
230     {
231         try
232         {
233             file.createNewFile();
234         }
235         catch ( IOException e )
236         {
237             // skip that
238         }
239     }
240
241     @Override
242     public void release( Lock lock )
243         throws FileLockException
244     {
245         if ( lock == null )
246         {
247             log.debug( "skip releasing null" );
248             return;
249         }
250         if ( skipLocking )
251         {
252             return;
253         }
254         try
255         {
256             lockFiles.remove( lock.getFile() );
257             lock.close();
258         }
259         catch ( IOException e )
260         {
261             throw new FileLockException( e.getMessage(), e );
262         }
263     }
264
265     public void clearLockFiles()
266     {
267         lockFiles.clear();
268     }
269
270     private boolean mkdirs( File directory )
271     {
272         if ( directory == null )
273         {
274             return false;
275         }
276
277         if ( directory.exists() )
278         {
279             return false;
280         }
281         if ( directory.mkdir() )
282         {
283             return true;
284         }
285
286         File canonDir = null;
287         try
288         {
289             canonDir = directory.getCanonicalFile();
290         }
291         catch ( IOException e )
292         {
293             return false;
294         }
295
296         File parentDir = canonDir.getParentFile();
297         return ( parentDir != null && ( mkdirs( parentDir ) || parentDir.exists() ) && canonDir.mkdir() );
298     }
299
300     public int getTimeout()
301     {
302         return timeout;
303     }
304
305     public void setTimeout( int timeout )
306     {
307         this.timeout = timeout;
308     }
309
310     public boolean isSkipLocking()
311     {
312         return skipLocking;
313     }
314
315     public void setSkipLocking( boolean skipLocking )
316     {
317         this.skipLocking = skipLocking;
318     }
319 }