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