]> source.dussan.org Git - archiva.git/blob
7d1011998074f2fcab7b7cf7da49659fe7d96751
[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 = new Lock( file, false );
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                     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                     log.debug( "read Lock skip: {} try to create file", e.getMessage() );
105                     createNewFileQuietly( file );
106                 }
107                 catch ( IOException e )
108                 {
109                     throw new FileLockException( e.getMessage(), e );
110                 }
111                 catch ( IllegalStateException e )
112                 {
113                     log.debug( "openLock {}:{}", e.getClass(), e.getMessage() );
114                 }
115             }
116             Lock current = lockFiles.putIfAbsent( file, lock );
117             if ( current != null )
118             {
119                 lock = current;
120             }
121             return lock;
122         }
123         catch ( IOException e )
124         {
125             throw new FileLockException( e.getMessage(), e );
126         }
127     }
128
129
130     @Override
131     public Lock writeFileLock( File file )
132         throws FileLockException, FileLockTimeoutException
133     {
134         if ( skipLocking )
135         {
136             return new Lock( file );
137         }
138
139         mkdirs( file.getParentFile() );
140
141         StopWatch stopWatch = new StopWatch();
142         boolean acquired = false;
143
144         try
145         {
146             Lock lock = new Lock( file, true );
147
148             stopWatch.start();
149
150             while ( !acquired )
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                 if ( current != null )
167                 {
168                     log.debug( "write lock file exist continue wait" );
169                     continue;
170                 }
171
172                 try
173                 {
174                     createNewFileQuietly( file );
175                     lock.openLock( true, timeout > 0 );
176                     acquired = true;
177                 }
178                 catch ( FileNotFoundException e )
179                 {
180                     // can happen if an other thread has deleted the file
181                     log.debug( "write Lock skip: {} try to create file", e.getMessage() );
182                     createNewFileQuietly( file );
183                 }
184                 catch ( IOException e )
185                 {
186                     throw new FileLockException( e.getMessage(), e );
187                 }
188                 catch ( IllegalStateException e )
189                 {
190                     log.debug( "openLock {}:{}", e.getClass(), e.getMessage() );
191                 }
192             }
193
194             Lock current = lockFiles.putIfAbsent( file, lock );
195             if ( current != null )
196             {
197                 lock = current;
198             }
199
200             return lock;
201         }
202
203         catch (
204
205             FileNotFoundException e
206
207             )
208
209         {
210             throw new FileLockException( e.getMessage(), e );
211         }
212
213     }
214
215     private void createNewFileQuietly( File file )
216     {
217         try
218         {
219             file.createNewFile();
220         }
221         catch ( IOException e )
222         {
223             // skip that
224         }
225     }
226
227     @Override
228     public void release( Lock lock )
229         throws FileLockException
230     {
231         if ( lock == null )
232         {
233             log.debug( "skip releasing null" );
234             return;
235         }
236         if ( skipLocking )
237         {
238             return;
239         }
240         try
241         {
242             lockFiles.remove( lock.getFile() );
243             lock.close();
244         }
245         catch ( IOException e )
246         {
247             throw new FileLockException( e.getMessage(), e );
248         }
249     }
250
251     public void clearLockFiles()
252     {
253         lockFiles.clear();
254     }
255
256     private boolean mkdirs( File directory )
257     {
258         if ( directory == null )
259         {
260             return false;
261         }
262
263         if ( directory.exists() )
264         {
265             return false;
266         }
267         if ( directory.mkdir() )
268         {
269             return true;
270         }
271
272         File canonDir = null;
273         try
274         {
275             canonDir = directory.getCanonicalFile();
276         }
277         catch ( IOException e )
278         {
279             return false;
280         }
281
282         File parentDir = canonDir.getParentFile();
283         return ( parentDir != null && ( mkdirs( parentDir ) || parentDir.exists() ) && canonDir.mkdir() );
284     }
285
286     public int getTimeout()
287     {
288         return timeout;
289     }
290
291     public void setTimeout( int timeout )
292     {
293         this.timeout = timeout;
294     }
295
296     public boolean isSkipLocking()
297     {
298         return skipLocking;
299     }
300
301     public void setSkipLocking( boolean skipLocking )
302     {
303         this.skipLocking = skipLocking;
304     }
305 }