3737import java .util .Optional ;
3838import java .util .concurrent .CompletableFuture ;
3939import java .util .concurrent .CompletionStage ;
40+ import java .util .concurrent .locks .Lock ;
41+ import java .util .concurrent .locks .ReadWriteLock ;
42+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
4043
4144public class LocalFsCloudProvider implements CloudProvider {
4245
4346 private static final CloudPath ABS_ROOT = CloudPath .of ("/" );
4447
4548 private final Path root ;
49+ private final ReadWriteLock lock ;
4650
4751 public LocalFsCloudProvider (Path root ) {
4852 this .root = root ;
53+ this .lock = new ReentrantReadWriteLock ();
4954 }
5055
5156 private Path resolve (CloudPath cloudPath ) {
@@ -64,6 +69,8 @@ private CloudItemMetadata createMetadata(Path fullPath, BasicFileAttributes attr
6469 @ Override
6570 public CompletionStage <CloudItemMetadata > itemMetadata (CloudPath node ) {
6671 Path path = resolve (node );
72+ Lock l = lock .readLock ();
73+ l .lock ();
6774 try {
6875 var attr = Files .readAttributes (path , BasicFileAttributes .class , LinkOption .NOFOLLOW_LINKS );
6976 var metadata = createMetadata (path , attr );
@@ -72,12 +79,16 @@ public CompletionStage<CloudItemMetadata> itemMetadata(CloudPath node) {
7279 return CompletableFuture .failedFuture (new NotFoundException (e ));
7380 } catch (IOException e ) {
7481 return CompletableFuture .failedFuture (new CloudProviderException (e ));
82+ } finally {
83+ l .unlock ();
7584 }
7685 }
7786
7887 @ Override
7988 public CompletionStage <CloudItemList > list (CloudPath folder , Optional <String > pageToken ) {
8089 Path folderPath = resolve (folder );
90+ Lock l = lock .readLock ();
91+ l .lock ();
8192 try {
8293 List <CloudItemMetadata > items = new ArrayList <>();
8394 var provider = this ;
@@ -96,12 +107,16 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
96107 return CompletableFuture .failedFuture (new TypeMismatchException (e ));
97108 } catch (IOException e ) {
98109 return CompletableFuture .failedFuture (new CloudProviderException (e ));
110+ } finally {
111+ l .unlock ();
99112 }
100113 }
101114
102115 @ Override
103116 public CompletionStage <InputStream > read (CloudPath file , long offset , long count , ProgressListener progressListener ) {
104117 Path filePath = resolve (file );
118+ Lock l = lock .readLock ();
119+ l .lock ();
105120 try {
106121 var ch = Files .newByteChannel (filePath , StandardOpenOption .READ );
107122 ch .position (offset );
@@ -110,6 +125,8 @@ public CompletionStage<InputStream> read(CloudPath file, long offset, long count
110125 return CompletableFuture .failedFuture (new NotFoundException (e ));
111126 } catch (IOException e ) {
112127 return CompletableFuture .failedFuture (new CloudProviderException (e ));
128+ } finally {
129+ l .unlock ();
113130 }
114131 }
115132
@@ -120,6 +137,8 @@ public CompletionStage<CloudItemMetadata> write(CloudPath file, boolean replace,
120137 ? EnumSet .of (StandardOpenOption .WRITE , StandardOpenOption .CREATE , StandardOpenOption .TRUNCATE_EXISTING )
121138 : EnumSet .of (StandardOpenOption .WRITE , StandardOpenOption .CREATE_NEW );
122139
140+ Lock l = lock .writeLock ();
141+ l .lock ();
123142 try (var ch = FileChannel .open (filePath , options )) {
124143 var tmpSize = ch .transferFrom (Channels .newChannel (data ), 0 , Long .MAX_VALUE );
125144 var modifiedDate = Files .getLastModifiedTime (filePath ).toInstant ();
@@ -131,39 +150,51 @@ public CompletionStage<CloudItemMetadata> write(CloudPath file, boolean replace,
131150 return CompletableFuture .failedFuture (new AlreadyExistsException (e ));
132151 } catch (IOException e ) {
133152 return CompletableFuture .failedFuture (new CloudProviderException (e ));
153+ } finally {
154+ l .unlock ();
134155 }
135156 }
136157
137158 @ Override
138159 public CompletionStage <CloudPath > createFolder (CloudPath folder ) {
139160 Path folderPath = resolve (folder );
161+ Lock l = lock .writeLock ();
162+ l .lock ();
140163 try {
141164 Files .createDirectory (folderPath );
142165 return CompletableFuture .completedFuture (folder );
143166 } catch (FileAlreadyExistsException e ) {
144167 return CompletableFuture .failedFuture (new AlreadyExistsException (e ));
145168 } catch (IOException e ) {
146169 return CompletableFuture .failedFuture (new CloudProviderException (e ));
170+ } finally {
171+ l .unlock ();
147172 }
148173 }
149174
150175 @ Override
151176 public CompletionStage <Void > delete (CloudPath node ) {
152177 Path path = resolve (node );
178+ Lock l = lock .writeLock ();
179+ l .lock ();
153180 try {
154181 MoreFiles .deleteRecursively (path , RecursiveDeleteOption .ALLOW_INSECURE );
155182 return CompletableFuture .completedFuture (null );
156183 } catch (NoSuchFileException e ) {
157184 return CompletableFuture .failedFuture (new NotFoundException (e ));
158185 } catch (IOException e ) {
159186 return CompletableFuture .failedFuture (new CloudProviderException (e ));
187+ } finally {
188+ l .unlock ();
160189 }
161190 }
162191
163192 @ Override
164193 public CompletionStage <CloudPath > move (CloudPath source , CloudPath target , boolean replace ) {
165194 Path src = resolve (source );
166195 Path dst = resolve (target );
196+ Lock l = lock .writeLock ();
197+ l .lock ();
167198 try {
168199 var options = replace ? EnumSet .of (StandardCopyOption .REPLACE_EXISTING ) : EnumSet .noneOf (StandardCopyOption .class );
169200 Files .move (src , dst , options .toArray (CopyOption []::new ));
@@ -174,6 +205,8 @@ public CompletionStage<CloudPath> move(CloudPath source, CloudPath target, boole
174205 return CompletableFuture .failedFuture (new AlreadyExistsException (e ));
175206 } catch (IOException e ) {
176207 return CompletableFuture .failedFuture (new CloudProviderException (e ));
208+ } finally {
209+ l .unlock ();
177210 }
178211 }
179212}
0 commit comments