1 | // $Id: PnfsHandler.java,v 1.35 2007-10-14 01:51:47 behrmann Exp $ |
2 | |
3 | package diskCacheV111.util ; |
4 | |
5 | import java.util.List; |
6 | import java.util.Collections; |
7 | import java.util.Set; |
8 | import java.util.EnumSet; |
9 | |
10 | import org.slf4j.Logger; |
11 | import org.slf4j.LoggerFactory; |
12 | |
13 | import dmg.cells.nucleus.CellEndpoint; |
14 | import dmg.cells.nucleus.CellPath; |
15 | import dmg.cells.nucleus.NoRouteToCellException; |
16 | |
17 | import diskCacheV111.vehicles.PnfsAddCacheLocationMessage; |
18 | import diskCacheV111.vehicles.PnfsClearCacheLocationMessage; |
19 | import diskCacheV111.vehicles.PnfsCreateDirectoryMessage; |
20 | import diskCacheV111.vehicles.PnfsCreateEntryMessage; |
21 | import diskCacheV111.vehicles.PnfsDeleteEntryMessage; |
22 | import diskCacheV111.vehicles.PnfsFlagMessage; |
23 | import diskCacheV111.vehicles.PnfsGetCacheLocationsMessage; |
24 | import diskCacheV111.vehicles.PnfsGetStorageInfoMessage; |
25 | import diskCacheV111.vehicles.PnfsMapPathMessage; |
26 | import diskCacheV111.vehicles.PnfsMessage; |
27 | import diskCacheV111.vehicles.PnfsRenameMessage; |
28 | import diskCacheV111.vehicles.PnfsSetFileMetaDataMessage; |
29 | import diskCacheV111.vehicles.PnfsSetLengthMessage; |
30 | import diskCacheV111.vehicles.PnfsSetStorageInfoMessage; |
31 | import diskCacheV111.vehicles.PnfsGetParentMessage; |
32 | import diskCacheV111.vehicles.PnfsSetChecksumMessage; |
33 | import diskCacheV111.vehicles.PoolFileFlushedMessage; |
34 | import diskCacheV111.vehicles.StorageInfo; |
35 | |
36 | import org.dcache.cells.CellMessageSender; |
37 | import org.dcache.cells.CellStub; |
38 | import org.dcache.auth.Subjects; |
39 | import org.dcache.namespace.FileAttribute; |
40 | import org.dcache.vehicles.FileAttributes; |
41 | import org.dcache.vehicles.PnfsGetFileAttributes; |
42 | import org.dcache.vehicles.PnfsSetFileAttributes; |
43 | import org.dcache.namespace.FileType; |
44 | import org.dcache.acl.enums.AccessMask; |
45 | import org.dcache.util.Checksum; |
46 | |
47 | import javax.security.auth.Subject; |
48 | |
49 | import static org.dcache.namespace.FileAttribute.*; |
50 | |
51 | public class PnfsHandler |
52 | implements CellMessageSender |
53 | { |
54 | private final String _poolName; |
55 | private static final long DEFAULT_PNFS_TIMEOUT = 30 * 60 * 1000L; |
56 | |
57 | private final CellStub _cellStub; |
58 | |
59 | private Subject _subject; |
60 | |
61 | private static final Logger _logNameSpace = |
62 | LoggerFactory.getLogger("logger.org.dcache.namespace." + PnfsHandler.class.getName()); |
63 | |
64 | private static CellStub createStub(CellPath path) |
65 | { |
66 | CellStub stub = new CellStub(); |
67 | stub.setDestinationPath(path); |
68 | stub.setTimeout(DEFAULT_PNFS_TIMEOUT); |
69 | stub.setRetryOnNoRouteToCell(true); |
70 | return stub; |
71 | } |
72 | |
73 | @Deprecated |
74 | public PnfsHandler(CellEndpoint endpoint, |
75 | CellPath pnfsManagerPath, |
76 | String poolName) |
77 | { |
78 | this(pnfsManagerPath, poolName); |
79 | setCellEndpoint(endpoint); |
80 | } |
81 | |
82 | @Deprecated |
83 | public PnfsHandler(CellEndpoint endpoint, |
84 | CellPath pnfsManagerPath) |
85 | { |
86 | this(pnfsManagerPath); |
87 | setCellEndpoint(endpoint); |
88 | } |
89 | |
90 | public PnfsHandler(CellPath pnfsManagerPath) |
91 | { |
92 | this(createStub(pnfsManagerPath)); |
93 | } |
94 | |
95 | public PnfsHandler(CellPath pnfsManagerPath, |
96 | String poolName) |
97 | { |
98 | this(createStub(pnfsManagerPath), poolName); |
99 | } |
100 | |
101 | public PnfsHandler(CellStub stub) |
102 | { |
103 | this(stub, "<client>"); |
104 | } |
105 | |
106 | public PnfsHandler(CellStub stub, String poolName) |
107 | { |
108 | _cellStub = stub; |
109 | _poolName = poolName; |
110 | } |
111 | |
112 | /** |
113 | * Copy constructor. The primary purpose is to create session |
114 | * specific PnfsHandlers with a session specific subject. Notice |
115 | * that the CellStub is shared between the two handlers and thus |
116 | * the timeout will always be the same. |
117 | * |
118 | * @param handler The PnfsHandler to copy |
119 | * @param subject The Subject to apply to the copy |
120 | */ |
121 | public PnfsHandler(PnfsHandler handler, Subject subject) |
122 | { |
123 | _poolName = handler._poolName; |
124 | _cellStub = handler._cellStub; |
125 | _subject = subject; |
126 | } |
127 | |
128 | @Override |
129 | public void setCellEndpoint(CellEndpoint endpoint) |
130 | { |
131 | _cellStub.setCellEndpoint(endpoint); |
132 | } |
133 | |
134 | public void setSubject(Subject subject) |
135 | { |
136 | _subject = subject; |
137 | } |
138 | |
139 | /** |
140 | * Sends a PnfsMessage to PnfsManager. |
141 | * |
142 | * @throws NoRouteToCellException if the PnfsManager could not be reached |
143 | */ |
144 | public void send(PnfsMessage msg) |
145 | throws NoRouteToCellException |
146 | { |
147 | if (_cellStub == null) { |
148 | throw new IllegalStateException("Missing endpoint"); |
149 | } |
150 | |
151 | if (_subject != null) { |
152 | msg.setSubject(_subject); |
153 | } |
154 | |
155 | _cellStub.send(msg); |
156 | } |
157 | |
158 | /** |
159 | * Sends a PnfsMessage notification to PnfsManager. No reply is |
160 | * expected for a notification and no failure is reported if the |
161 | * message could not be delivered. |
162 | */ |
163 | public void notify(PnfsMessage msg) |
164 | { |
165 | try { |
166 | msg.setReplyRequired(false); |
167 | send(msg); |
168 | } catch (NoRouteToCellException e) { |
169 | _logNameSpace.warn("Failed to deliver message " + |
170 | msg.getClass().getSimpleName() + |
171 | " to PnfsManager: " + e.getMessage()); |
172 | } |
173 | } |
174 | |
175 | public void clearCacheLocation( PnfsId pnfsId ){ |
176 | clearCacheLocation( pnfsId , false ); |
177 | } |
178 | public void clearCacheLocation( PnfsId pnfsId , boolean removeIfLast ){ |
179 | |
180 | notify( new PnfsClearCacheLocationMessage( |
181 | pnfsId, |
182 | _poolName, |
183 | removeIfLast) |
184 | ) ; |
185 | |
186 | } |
187 | public void clearCacheLocation( PnfsId pnfsId , String poolName ){ |
188 | |
189 | notify( new PnfsClearCacheLocationMessage( |
190 | pnfsId, |
191 | poolName) |
192 | ) ; |
193 | |
194 | } |
195 | |
196 | public void addCacheLocation( PnfsId pnfsId ) |
197 | throws CacheException |
198 | { |
199 | pnfsRequest( new PnfsAddCacheLocationMessage( |
200 | pnfsId, |
201 | _poolName) |
202 | ) ; |
203 | |
204 | } |
205 | |
206 | public void setFileSize( PnfsId pnfsId , long length )throws CacheException { |
207 | |
208 | pnfsRequest( new PnfsSetLengthMessage( |
209 | pnfsId, |
210 | length ) |
211 | ) ; |
212 | |
213 | } |
214 | public List<String> getCacheLocations( PnfsId pnfsId )throws CacheException { |
215 | PnfsGetCacheLocationsMessage pnfsMessage = new PnfsGetCacheLocationsMessage(pnfsId) ; |
216 | pnfsMessage = pnfsRequest(pnfsMessage) ; |
217 | List<String> assumedLocations = pnfsMessage.getCacheLocations() ; |
218 | |
219 | if (assumedLocations == null) { |
220 | return Collections.emptyList(); |
221 | } else { |
222 | return assumedLocations; |
223 | } |
224 | } |
225 | |
226 | public List<String> getCacheLocationsByPath( String fileName )throws CacheException { |
227 | PnfsGetCacheLocationsMessage pnfsMessage = new PnfsGetCacheLocationsMessage() ; |
228 | pnfsMessage.setPnfsPath( fileName ) ; |
229 | pnfsMessage = pnfsRequest(pnfsMessage) ; |
230 | List<String> assumedLocations = pnfsMessage.getCacheLocations() ; |
231 | |
232 | if (assumedLocations == null) { |
233 | return Collections.emptyList(); |
234 | } else { |
235 | return assumedLocations; |
236 | } |
237 | } |
238 | |
239 | /** |
240 | * Sends a message to the request manager and blocks until a reply |
241 | * is received. In case of errors in the reply, those are thrown |
242 | * as a CacheException. Timeouts and failure to send the message |
243 | * to the PnfsManager are reported as a timeout CacheException. |
244 | */ |
245 | public <T extends PnfsMessage> T pnfsRequest( T msg ) |
246 | throws CacheException { |
247 | |
248 | if (_cellStub == null) |
249 | throw new IllegalStateException("Missing endpoint"); |
250 | |
251 | try { |
252 | msg.setReplyRequired(true); |
253 | if (_subject != null) { |
254 | msg.setSubject(_subject); |
255 | } |
256 | return _cellStub.sendAndWait(msg); |
257 | } catch (InterruptedException e) { |
258 | throw new CacheException(CacheException.UNEXPECTED_SYSTEM_EXCEPTION, |
259 | "Sending message to PnafsManager intterupted"); |
260 | } |
261 | } |
262 | |
263 | public PnfsCreateEntryMessage createPnfsDirectory(String path) |
264 | throws CacheException |
265 | { |
266 | return pnfsRequest(new PnfsCreateDirectoryMessage(path)); |
267 | } |
268 | |
269 | public PnfsCreateEntryMessage createPnfsDirectory(String path, int uid, int gid, int mode) |
270 | throws CacheException |
271 | { |
272 | return pnfsRequest(new PnfsCreateDirectoryMessage(path, uid, gid, mode)); |
273 | } |
274 | |
275 | /** |
276 | * Creates a directory and all its parent directories. |
277 | * |
278 | * REVISIT: Should eventually be moved to PnfsManager with a flag |
279 | * in the PnfsCreateEntryMessage indicating whether parent |
280 | * directories should be created. |
281 | * |
282 | * @returns the FileAttributes of <code>path</code> |
283 | */ |
284 | public FileAttributes createDirectories(FsPath path) |
285 | throws CacheException |
286 | { |
287 | PnfsCreateEntryMessage message; |
288 | try { |
289 | message = createPnfsDirectory(path.toString()); |
290 | } catch (FileNotFoundCacheException e) { |
291 | createDirectories(path.getParent()); |
292 | message = createPnfsDirectory(path.toString()); |
293 | } |
294 | |
295 | /* In case of incomplete create, delete the directory right |
296 | * away. |
297 | */ |
298 | if (message.getStorageInfo() == null) { |
299 | try { |
300 | deletePnfsEntry(message.getPnfsId(), path.toString()); |
301 | } catch (FileNotFoundCacheException e) { |
302 | // Already gone, so never mind |
303 | } catch (CacheException e) { |
304 | _logNameSpace.error(e.toString()); |
305 | } |
306 | |
307 | throw new CacheException("Failed to create directory: " + path); |
308 | } |
309 | |
310 | return message.getFileAttributes(); |
311 | } |
312 | |
313 | public PnfsCreateEntryMessage createPnfsEntry( String path ) |
314 | throws CacheException { |
315 | |
316 | return pnfsRequest(new PnfsCreateEntryMessage( path )) ; |
317 | |
318 | } |
319 | |
320 | public void pnfsSetFileMetaData(PnfsId pnfsId, FileMetaData meta) |
321 | throws CacheException |
322 | { |
323 | pnfsRequest(new PnfsSetFileMetaDataMessage(pnfsId, meta)); |
324 | } |
325 | |
326 | public void renameEntry(PnfsId pnfsId, String newName) |
327 | throws CacheException |
328 | { |
329 | renameEntry(pnfsId, newName, true); |
330 | } |
331 | |
332 | public void renameEntry(PnfsId pnfsId, String newName, boolean overwrite) |
333 | throws CacheException |
334 | { |
335 | pnfsRequest(new PnfsRenameMessage(pnfsId, newName, overwrite)); |
336 | } |
337 | |
338 | public void renameEntry(String path, String newName, boolean overwrite) |
339 | throws CacheException |
340 | { |
341 | pnfsRequest(new PnfsRenameMessage(path, newName, overwrite)); |
342 | } |
343 | |
344 | public PnfsCreateEntryMessage createPnfsEntry( String path , int uid , int gid , int mode ) |
345 | throws CacheException { |
346 | |
347 | return pnfsRequest( new PnfsCreateEntryMessage( path , uid , gid , mode ) ) ; |
348 | |
349 | } |
350 | |
351 | public void setStorageInfoByPnfsId( |
352 | PnfsId pnfsId , StorageInfo storageInfo , int accessMode ) |
353 | throws CacheException { |
354 | |
355 | /* |
356 | * use request, which throws exceptions in case of..... |
357 | */ |
358 | pnfsRequest( new PnfsSetStorageInfoMessage( pnfsId , storageInfo , accessMode ) ) ; |
359 | } |
360 | public PnfsGetStorageInfoMessage getStorageInfoByPnfsId( PnfsId pnfsId ) |
361 | throws CacheException { |
362 | return pnfsRequest(new PnfsGetStorageInfoMessage( pnfsId )) ; |
363 | |
364 | } |
365 | |
366 | public PnfsGetStorageInfoMessage getStorageInfoByPath( String pnfsPath ) |
367 | throws CacheException { |
368 | return getStorageInfoByPath(pnfsPath, false) ; |
369 | |
370 | } |
371 | |
372 | public PnfsGetStorageInfoMessage getStorageInfoByPath( String pnfsPath , |
373 | boolean requestChecksum) |
374 | throws CacheException { |
375 | |
376 | PnfsGetStorageInfoMessage sInfo = new PnfsGetStorageInfoMessage() ; |
377 | sInfo.setPnfsPath( pnfsPath ) ; |
378 | sInfo.setChecksumsRequested(requestChecksum); |
379 | return pnfsRequest( sInfo ) ; |
380 | |
381 | } |
382 | |
383 | public PnfsId getParentOf(PnfsId pnfsId) |
384 | throws CacheException |
385 | { |
386 | return pnfsRequest(new PnfsGetParentMessage(pnfsId)).getParent(); |
387 | } |
388 | |
389 | public void deletePnfsEntry(String path) throws CacheException |
390 | { |
391 | deletePnfsEntry(null, path); |
392 | } |
393 | |
394 | public void deletePnfsEntry(String path, Set<FileType> allowed) |
395 | throws CacheException |
396 | { |
397 | deletePnfsEntry(null, path, allowed); |
398 | } |
399 | |
400 | public void deletePnfsEntry(PnfsId pnfsid) throws CacheException |
401 | { |
402 | deletePnfsEntry(pnfsid, null); |
403 | } |
404 | |
405 | public void deletePnfsEntry(PnfsId pnfsid, String path) |
406 | throws CacheException |
407 | { |
408 | deletePnfsEntry(pnfsid, path, EnumSet.allOf(FileType.class)); |
409 | } |
410 | |
411 | public void deletePnfsEntry(PnfsId pnfsid, String path, |
412 | Set<FileType> allowed) |
413 | throws CacheException |
414 | { |
415 | pnfsRequest(new PnfsDeleteEntryMessage(pnfsid, path, allowed)); |
416 | } |
417 | |
418 | /** |
419 | * Getter for property __pnfsTimeout. |
420 | * @return Value of property __pnfsTimeout. |
421 | */ |
422 | public long getPnfsTimeout() { |
423 | return _cellStub.getTimeout(); |
424 | } |
425 | |
426 | /** |
427 | * Setter for property __pnfsTimeout. |
428 | * @param __pnfsTimeout New value of property __pnfsTimeout. |
429 | */ |
430 | public void setPnfsTimeout(long pnfsTimeout) { |
431 | _cellStub.setTimeout(pnfsTimeout); |
432 | } |
433 | |
434 | public String getPnfsFlag(PnfsId pnfsId, String flag) |
435 | throws CacheException |
436 | { |
437 | PnfsFlagMessage flagMessage = |
438 | new PnfsFlagMessage( pnfsId ,flag , PnfsFlagMessage.FlagOperation.GET ) ; |
439 | flagMessage.setReplyRequired( true ); |
440 | |
441 | return pnfsRequest(flagMessage).getValue(); |
442 | } |
443 | |
444 | public void putPnfsFlag(PnfsId pnfsId, String flag, String value) |
445 | { |
446 | PnfsFlagMessage flagMessage = |
447 | new PnfsFlagMessage( pnfsId ,flag , PnfsFlagMessage.FlagOperation.SET ) ; |
448 | flagMessage.setReplyRequired( false ); |
449 | flagMessage.setValue(value); |
450 | notify(flagMessage); |
451 | } |
452 | |
453 | public void fileFlushed(PnfsId pnfsId, StorageInfo storageInfo ) throws CacheException { |
454 | |
455 | PoolFileFlushedMessage fileFlushedMessage = new PoolFileFlushedMessage(_poolName, pnfsId, storageInfo); |
456 | |
457 | // throws exception if something goes wrong |
458 | pnfsRequest(fileFlushedMessage); |
459 | |
460 | } |
461 | |
462 | /** |
463 | * Get path corresponding to given pnfsid. |
464 | * |
465 | * @param pnfsID |
466 | * @return path |
467 | * @throws CacheException |
468 | */ |
469 | public String getPathByPnfsId(PnfsId pnfsID) throws CacheException { |
470 | return pnfsRequest(new PnfsMapPathMessage(pnfsID)).getGlobalPath(); |
471 | } |
472 | |
473 | /** |
474 | * Get pnfsid corresponding to given path. |
475 | * |
476 | * @param path |
477 | * @return pnfsid |
478 | * @throws CacheException |
479 | */ |
480 | public PnfsId getPnfsIdByPath(String path) throws CacheException { |
481 | return pnfsRequest(new PnfsMapPathMessage(path)).getPnfsId(); |
482 | } |
483 | |
484 | /** |
485 | * Get file attributes. The PnfsManager is free to return less attributes |
486 | * than requested. If <code>attr</code> is an empty array, file existence |
487 | * if checked. |
488 | * |
489 | * @param pnfsid |
490 | * @param attr array of requested attributes. |
491 | * @return requested attributes |
492 | */ |
493 | public FileAttributes getFileAttributes(PnfsId pnfsid, Set<FileAttribute> attr) throws CacheException { |
494 | return pnfsRequest(new PnfsGetFileAttributes(pnfsid, attr)).getFileAttributes(); |
495 | } |
496 | |
497 | /** |
498 | * Get file attributes. The PnfsManager is free to return less attributes |
499 | * than requested. If <code>attr</code> is an empty array, file existence |
500 | * if checked. |
501 | * |
502 | * @param pnfsid |
503 | * @param attr array of requested attributes. |
504 | * @param mask Additional AccessMask access rights to check |
505 | * @return requested attributes |
506 | */ |
507 | public FileAttributes getFileAttributes(PnfsId pnfsid, Set<FileAttribute> attr, Set<AccessMask> mask) |
508 | throws CacheException |
509 | { |
510 | PnfsGetFileAttributes msg = new PnfsGetFileAttributes(pnfsid, attr); |
511 | msg.setAccessMask(mask); |
512 | return pnfsRequest(msg).getFileAttributes(); |
513 | } |
514 | |
515 | /** |
516 | * Get file attributes. The PnfsManager is free to return less attributes |
517 | * than requested. If <code>attr</code> is an empty array, file existence |
518 | * if checked. |
519 | * |
520 | * @param path |
521 | * @param attr array of requested attributes. |
522 | * @return requested attributes |
523 | */ |
524 | public FileAttributes getFileAttributes(String path, Set<FileAttribute> attr) |
525 | throws CacheException |
526 | { |
527 | return pnfsRequest(new PnfsGetFileAttributes(path, attr)).getFileAttributes(); |
528 | } |
529 | |
530 | /** |
531 | * Get file attributes. The PnfsManager is free to return less attributes |
532 | * than requested. If <code>attr</code> is an empty array, file existence |
533 | * if checked. |
534 | * |
535 | * @param path |
536 | * @param attr array of requested attributes. |
537 | * @param mask Additional AccessMask access rights to check |
538 | * @return requested attributes |
539 | */ |
540 | public FileAttributes getFileAttributes(String path, |
541 | Set<FileAttribute> attr, |
542 | Set<AccessMask> mask) |
543 | throws CacheException |
544 | { |
545 | PnfsGetFileAttributes msg = new PnfsGetFileAttributes(path, attr); |
546 | msg.setAccessMask(mask); |
547 | return pnfsRequest(msg).getFileAttributes(); |
548 | } |
549 | |
550 | /** |
551 | * Set file attributes. If <code>attr</code> is an empty array, |
552 | * file existence if checked. |
553 | * |
554 | * @param pnfsid |
555 | * @param attr array of requested attributes. |
556 | * @return requested attributes |
557 | */ |
558 | public void setFileAttributes(PnfsId pnfsid, FileAttributes attr) |
559 | throws CacheException |
560 | { |
561 | pnfsRequest(new PnfsSetFileAttributes(pnfsid, attr)); |
562 | } |
563 | |
564 | public void setChecksum(PnfsId pnfsId, Checksum checksum) |
565 | throws CacheException |
566 | { |
567 | PnfsSetChecksumMessage message = |
568 | new PnfsSetChecksumMessage(pnfsId, |
569 | checksum.getType().getType(), |
570 | checksum.getValue()); |
571 | pnfsRequest(message); |
572 | } |
573 | } |