1 11 package org.eclipse.osgi.storagemanager; 12 13 import java.io.*; 14 import java.security.AccessController ; 15 import java.util.*; 16 import org.eclipse.core.runtime.internal.adaptor.*; 17 import org.eclipse.osgi.framework.internal.reliablefile.*; 18 import org.eclipse.osgi.framework.util.SecureAction; 19 20 82 83 public final class StorageManager { 87 private static final int FILETYPE_STANDARD = 0; 88 private static final int FILETYPE_RELIABLEFILE = 1; 89 private static final SecureAction secure = (SecureAction) AccessController.doPrivileged(SecureAction.createSecureAction()); 90 private static boolean tempCleanup = Boolean.valueOf(secure.getProperty("osgi.embedded.cleanTempFiles")).booleanValue(); private static boolean openCleanup = Boolean.valueOf(secure.getProperty("osgi.embedded.cleanupOnOpen")).booleanValue(); private static final String MANAGER_FOLDER = ".manager"; private static final String TABLE_FILE = ".fileTable"; private static final String LOCK_FILE = ".fileTableLock"; private static final int MAX_LOCK_WAIT = 5000; 97 private class Entry { 98 int readId; 99 int writeId; 100 int fileType; 101 102 Entry(int readId, int writeId, int type) { 103 this.readId = readId; 104 this.writeId = writeId; 105 this.fileType = type; 106 } 107 108 int getReadId() { 109 return readId; 110 } 111 112 int getWriteId() { 113 return writeId; 114 } 115 116 int getFileType() { 117 return fileType; 118 } 119 120 void setReadId(int value) { 121 readId = value; 122 } 123 124 void setWriteId(int value) { 125 writeId = value; 126 } 127 128 void setFileType(int type) { 129 fileType = type; 130 } 131 } 132 133 private File base; private File managerRoot; 136 private String lockMode = null; 137 private File tableFile = null; 138 private File lockFile; private Locker locker; 141 private File instanceFile = null; private Locker instanceLocker = null; private boolean readOnly; private boolean open; 146 private int tableStamp = -1; 148 149 private Properties table = new Properties(); 150 private boolean useReliableFiles = Boolean.valueOf(secure.getProperty("osgi.useReliableFiles")).booleanValue(); 152 160 public StorageManager(File base, String lockMode) { 161 this(base, lockMode, false); 162 } 163 164 173 public StorageManager(File base, String lockMode, boolean readOnly) { 174 this.base = base; 175 this.lockMode = lockMode; 176 this.managerRoot = new File(base, MANAGER_FOLDER); 177 if (!readOnly) 178 this.managerRoot.mkdirs(); 179 this.tableFile = new File(managerRoot, TABLE_FILE); 180 this.lockFile = new File(managerRoot, LOCK_FILE); 181 this.readOnly = readOnly; 182 open = false; 183 } 184 185 private void initializeInstanceFile() throws IOException { 186 if (instanceFile != null || readOnly) 187 return; 188 this.instanceFile = File.createTempFile(".tmp", ".instance", managerRoot); this.instanceFile.deleteOnExit(); 190 instanceLocker = BasicLocation.createLocker(instanceFile, lockMode); 191 instanceLocker.lock(); 192 } 193 194 private String getAbsolutePath(String file) { 195 return new File(base, file).getAbsolutePath(); 196 } 197 198 204 public void add(String managedFile) throws IOException { 205 add(managedFile, FILETYPE_STANDARD); 206 } 207 208 215 private void add(String managedFile, int fileType) throws IOException { 216 if (!open) 217 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 218 if (readOnly) 219 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 220 if (!lock(true)) 221 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 222 try { 223 updateTable(); 224 Entry entry = (Entry) table.get(managedFile); 225 if (entry == null) { 226 entry = new Entry(0, 1, fileType); 227 table.put(managedFile, entry); 228 int oldestGeneration = findOldestGeneration(managedFile); 232 if (oldestGeneration != 0) 233 entry.setWriteId(oldestGeneration + 1); 234 save(); 235 } else { 236 if (entry.getFileType() != fileType) { 237 entry.setFileType(fileType); 238 updateTable(); 239 save(); 240 } 241 } 242 } finally { 243 release(); 244 } 245 } 246 247 253 private int findOldestGeneration(String managedFile) { 254 String [] files = base.list(); 255 int oldestGeneration = 0; 256 if (files != null) { 257 String name = managedFile + '.'; 258 int len = name.length(); 259 for (int i = 0; i < files.length; i++) { 260 if (!files[i].startsWith(name)) 261 continue; 262 try { 263 int generation = Integer.parseInt(files[i].substring(len)); 264 if (generation > oldestGeneration) 265 oldestGeneration = generation; 266 } catch (NumberFormatException e) { 267 continue; 268 } 269 } 270 } 271 return oldestGeneration; 272 } 273 274 286 public void update(String [] managedFiles, String [] sources) throws IOException { 287 if (!open) 288 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 289 if (readOnly) 290 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 291 if (!lock(true)) 292 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 293 try { 294 updateTable(); 295 int[] originalReadIDs = new int[managedFiles.length]; 296 boolean error = false; 297 for (int i = 0; i < managedFiles.length; i++) { 298 originalReadIDs[i] = getId(managedFiles[i]); 299 if (!update(managedFiles[i], sources[i])) 300 error = true; 301 } 302 if (error) { 303 for (int i = 0; i < managedFiles.length; i++) { 305 Entry entry = (Entry) table.get(managedFiles[i]); 306 entry.setReadId(originalReadIDs[i]); 307 } 308 throw new IOException(EclipseAdaptorMsg.fileManager_updateFailed); 309 } 310 save(); } finally { 312 release(); 313 } 314 } 315 316 321 public String [] getManagedFiles() { 322 if (!open) 323 return null; 324 Set set = table.keySet(); 325 String [] keys = (String []) set.toArray(new String [set.size()]); 326 String [] result = new String [keys.length]; 327 for (int i = 0; i < keys.length; i++) 328 result[i] = new String (keys[i]); 329 return result; 330 } 331 332 338 public File getBase() { 339 return base; 340 } 341 342 350 public int getId(String managedFile) { 351 if (!open) 352 return -1; 353 Entry entry = (Entry) table.get(managedFile); 354 if (entry == null) 355 return -1; 356 return entry.getReadId(); 357 } 358 359 364 public boolean isReadOnly() { 365 return readOnly; 366 } 367 368 380 private boolean lock(boolean wait) throws IOException { 381 if (readOnly) 382 return false; 383 if (locker == null) { 384 locker = BasicLocation.createLocker(lockFile, lockMode); 385 if (locker == null) 386 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 387 } 388 boolean locked = locker.lock(); 389 if (locked || !wait) 390 return locked; 391 long start = System.currentTimeMillis(); 393 while (true) { 394 try { 395 Thread.sleep(200); } catch (InterruptedException e) { 397 } 398 locked = locker.lock(); 399 if (locked) 400 return true; 401 long time = System.currentTimeMillis() - start; 403 if (time > MAX_LOCK_WAIT) 404 return false; 405 } 406 } 407 408 423 public File lookup(String managedFile, boolean add) throws IOException { 424 if (!open) 425 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 426 Entry entry = (Entry) table.get(managedFile); 427 if (entry == null) { 428 if (add) { 429 add(managedFile); 430 entry = (Entry) table.get(managedFile); 431 } else { 432 return null; 433 } 434 } 435 return new File(getAbsolutePath(managedFile + '.' + entry.getReadId())); 436 } 437 438 private boolean move(String source, String managedFile) { 439 File original = new File(source); 440 File targetFile = new File(managedFile); 441 if (!original.exists() || targetFile.exists()) 444 return false; 445 return original.renameTo(targetFile); 446 } 447 448 451 private void release() { 452 if (locker == null) 453 return; 454 locker.release(); 455 } 456 457 463 public void remove(String managedFile) throws IOException { 464 if (!open) 465 throw new IOException(EclipseAdaptorMsg.fileManager_notOpen); 466 if (readOnly) 467 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 468 if (!lock(true)) 471 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 472 try { 473 updateTable(); 474 table.remove(managedFile); 475 save(); 476 } finally { 477 release(); 478 } 479 } 480 481 private void updateTable() throws IOException { 482 int stamp; 483 stamp = ReliableFile.lastModifiedVersion(tableFile); 484 if (stamp == tableStamp || stamp == -1) 485 return; 486 Properties diskTable = new Properties(); 487 try { 488 InputStream input; 489 input = new ReliableFileInputStream(tableFile); 490 try { 491 diskTable.load(input); 492 } finally { 493 input.close(); 494 } 495 } catch (IOException e) { 496 throw e; } 498 tableStamp = stamp; 499 for (Enumeration e = diskTable.keys(); e.hasMoreElements();) { 500 String file = (String ) e.nextElement(); 501 String value = diskTable.getProperty(file); 502 if (value != null) { 503 Entry entry = (Entry) table.get(file); 504 int id; 506 int fileType; 507 int idx = value.indexOf(','); 508 if (idx != -1) { 509 id = Integer.parseInt(value.substring(0, idx)); 510 fileType = Integer.parseInt(value.substring(idx + 1)); 511 } else { 512 id = Integer.parseInt(value); 513 fileType = FILETYPE_STANDARD; 514 } 515 if (entry == null) { 516 table.put(file, new Entry(id, id + 1, fileType)); 517 } else { 518 entry.setWriteId(id + 1); 519 } 521 } 522 } 523 } 524 525 528 private void save() throws IOException { 529 if (readOnly) 530 return; 531 updateTable(); 534 535 Properties props = new Properties(); 536 for (Enumeration e = table.keys(); e.hasMoreElements();) { 537 String file = (String ) e.nextElement(); 538 Entry entry = (Entry) table.get(file); 539 String value; 540 if (entry.getFileType() != FILETYPE_STANDARD) { 541 value = Integer.toString(entry.getWriteId() - 1) + ',' + Integer.toString(entry.getFileType()); 543 } else { 544 value = Integer.toString(entry.getWriteId() - 1); } 546 props.put(file, value); 547 } 548 ReliableFileOutputStream fileStream = new ReliableFileOutputStream(tableFile); 549 try { 550 boolean error = true; 551 try { 552 props.store(fileStream, "safe table"); fileStream.close(); 554 error = false; 555 } finally { 556 if (error) 557 fileStream.abort(); 558 } 559 } catch (IOException e) { 560 throw new IOException(EclipseAdaptorMsg.fileManager_couldNotSave); 561 } 562 tableStamp = ReliableFile.lastModifiedVersion(tableFile); 563 } 564 565 private boolean update(String managedFile, String source) throws IOException { 566 Entry entry = (Entry) table.get(managedFile); 567 if (entry == null) 568 add(managedFile); 569 int newId = entry.getWriteId(); 570 boolean success = move(getAbsolutePath(source), getAbsolutePath(managedFile) + '.' + newId); 572 if (!success) { 573 newId = findOldestGeneration(managedFile) + 1; 576 success = move(getAbsolutePath(source), getAbsolutePath(managedFile) + '.' + newId); 577 } 578 if (!success) 579 return false; 580 entry.setReadId(newId); 583 entry.setWriteId(newId + 1); 584 return true; 585 } 586 587 592 private void cleanup() throws IOException { 593 if (readOnly) 594 return; 595 if (!lock(true)) 597 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 598 try { 599 String [] files = managerRoot.list(); 601 if (files != null) { 602 for (int i = 0; i < files.length; i++) { 603 if (files[i].endsWith(".instance") && instanceFile != null && !files[i].equalsIgnoreCase(instanceFile.getName())) { Locker tmpLocker = BasicLocation.createLocker(new File(managerRoot, files[i]), lockMode); 605 if (tmpLocker.lock()) { 606 tmpLocker.release(); 608 new File(managerRoot, files[i]).delete(); 609 } else { 610 tmpLocker.release(); 611 return; } 613 } 614 } 615 } 616 617 updateTable(); 619 Collection managedFiles = table.entrySet(); 620 for (Iterator iter = managedFiles.iterator(); iter.hasNext();) { 621 Map.Entry fileEntry = (Map.Entry) iter.next(); 622 String fileName = (String ) fileEntry.getKey(); 623 Entry info = (Entry) fileEntry.getValue(); 624 if (info.getFileType() == FILETYPE_RELIABLEFILE) { 625 ReliableFile.cleanupGenerations(new File(base, fileName)); 626 } else { 627 String readId = Integer.toString(info.getWriteId() - 1); 629 deleteCopies(fileName, readId); 630 } 631 } 632 633 if (tempCleanup) { 634 files = base.list(); 635 if (files != null) { 636 for (int i = 0; i < files.length; i++) { 637 if (files[i].endsWith(ReliableFile.tmpExt)) { 638 new File(base, files[i]).delete(); 639 } 640 } 641 } 642 } 643 } catch (IOException e) { 644 throw e; 647 } finally { 648 release(); 649 } 650 } 651 652 private void deleteCopies(String fileName, String exceptionNumber) { 653 String notToDelete = fileName + '.' + exceptionNumber; 654 String [] files = base.list(); 655 if (files == null) 656 return; 657 for (int i = 0; i < files.length; i++) { 658 if (files[i].startsWith(fileName + '.') && !files[i].equals(notToDelete)) 659 new File(base, files[i]).delete(); 660 } 661 } 662 663 667 public void close() { 668 if (!open) 669 return; 670 open = false; 671 if (readOnly) 672 return; 673 try { 674 cleanup(); 675 } catch (IOException e) { 676 } 678 if (instanceLocker != null) 679 instanceLocker.release(); 680 681 if (instanceFile != null) 682 instanceFile.delete(); 683 } 684 685 691 public void open(boolean wait) throws IOException { 692 if (openCleanup) 693 cleanup(); 694 if (!readOnly) { 695 boolean locked = lock(wait); 696 if (!locked && wait) 697 throw new IOException(EclipseAdaptorMsg.fileManager_cannotLock); 698 } 699 700 try { 701 initializeInstanceFile(); 702 updateTable(); 703 open = true; 704 } finally { 705 release(); 706 } 707 } 708 709 718 public File createTempFile(String file) throws IOException { 719 if (readOnly) 720 throw new IOException(EclipseAdaptorMsg.fileManager_illegalInReadOnlyMode); 721 File tmpFile = File.createTempFile(file, ReliableFile.tmpExt, base); 722 tmpFile.deleteOnExit(); 723 return tmpFile; 724 } 725 726 735 public InputStream getInputStream(String managedFile) throws IOException { 736 return getInputStream(managedFile, ReliableFile.OPEN_BEST_AVAILABLE); 737 } 738 739 749 public InputStream[] getInputStreamSet(String [] managedFiles) throws IOException { 750 InputStream[] streams = new InputStream[managedFiles.length]; 751 for (int i = 0; i < streams.length; i++) 752 streams[i] = getInputStream(managedFiles[i], ReliableFile.OPEN_FAIL_ON_PRIMARY); 753 return streams; 754 } 755 756 private InputStream getInputStream(String managedFiles, int openMask) throws IOException { 757 if (useReliableFiles) { 758 int id = getId(managedFiles); 759 if (id == -1) 760 return null; 761 return new ReliableFileInputStream(new File(getBase(), managedFiles), id, openMask); 762 } 763 File lookup = lookup(managedFiles, false); 764 if (lookup == null) 765 return null; 766 return new FileInputStream(lookup); 767 } 768 769 778 public ManagedOutputStream getOutputStream(String managedFile) throws IOException { 779 if (useReliableFiles) { 780 ReliableFileOutputStream out = new ReliableFileOutputStream(new File(getBase(), managedFile)); 781 return new ManagedOutputStream(out, this, managedFile, null); 782 } 783 File tmpFile = createTempFile(managedFile); 784 return new ManagedOutputStream(new FileOutputStream(tmpFile), this, managedFile, tmpFile); 785 } 786 787 798 public ManagedOutputStream[] getOutputStreamSet(String [] managedFiles) throws IOException { 799 int count = managedFiles.length; 800 ManagedOutputStream[] streams = new ManagedOutputStream[count]; 801 int idx = 0; 802 try { 803 for (; idx < count; idx++) { 804 ManagedOutputStream newStream = getOutputStream(managedFiles[idx]); 805 newStream.setStreamSet(streams); 806 streams[idx] = newStream; 807 } 808 } catch (IOException e) { 809 for (int jdx = 0; jdx < idx; jdx++) 811 streams[jdx].abort(); 812 throw e; 813 } 814 return streams; 815 } 816 817 827 void abortOutputStream(ManagedOutputStream out) { 828 ManagedOutputStream[] set = out.getStreamSet(); 829 if (set == null) { 830 set = new ManagedOutputStream[] {out}; 831 } 832 synchronized (set) { 833 for (int idx = 0; idx < set.length; idx++) { 834 out = set[idx]; 835 if (out.getOutputFile() == null) { 836 ReliableFileOutputStream rfos = (ReliableFileOutputStream) out.getOutputStream(); 838 rfos.abort(); 839 } else { 840 if (out.getState() == ManagedOutputStream.ST_OPEN) { 842 try { 843 out.getOutputStream().close(); 844 } catch (IOException e) { 845 } 846 } 847 out.getOutputFile().delete(); 848 } 849 out.setState(ManagedOutputStream.ST_CLOSED); 850 } 851 } 852 } 853 854 864 void closeOutputStream(ManagedOutputStream smos) throws IOException { 865 if (smos.getState() != ManagedOutputStream.ST_OPEN) 866 return; 867 ManagedOutputStream[] streamSet = smos.getStreamSet(); 868 if (smos.getOutputFile() == null) { 869 ReliableFileOutputStream rfos = (ReliableFileOutputStream) smos.getOutputStream(); 871 File file = rfos.closeIntermediateFile(); 873 smos.setState(ManagedOutputStream.ST_CLOSED); 874 String target = smos.getTarget(); 875 if (streamSet == null) { 876 add(target, StorageManager.FILETYPE_RELIABLEFILE); 877 update(new String [] {smos.getTarget()}, new String [] {file.getName()}); 878 ReliableFile.fileUpdated(new File(getBase(), smos.getTarget())); 879 } 880 } else { 881 OutputStream out = smos.getOutputStream(); 883 out.flush(); 884 try { 885 ((FileOutputStream) out).getFD().sync(); 886 } catch (SyncFailedException e) { 887 } 888 out.close(); 889 smos.setState(ManagedOutputStream.ST_CLOSED); 890 String target = smos.getTarget(); 891 if (streamSet == null) { 892 add(target, StorageManager.FILETYPE_STANDARD); 893 update(new String [] {target}, new String [] {smos.getOutputFile().getName()}); 894 } 895 } 896 897 if (streamSet != null) { 898 synchronized (streamSet) { 899 for (int idx = 0; idx < streamSet.length; idx++) { 901 if (streamSet[idx].getState() == ManagedOutputStream.ST_OPEN) 902 return; } 904 String [] targets = new String [streamSet.length]; 906 String [] sources = new String [streamSet.length]; 907 for (int idx = 0; idx < streamSet.length; idx++) { 908 smos = streamSet[idx]; 909 targets[idx] = smos.getTarget(); 910 File outputFile = smos.getOutputFile(); 911 if (outputFile == null) { 912 add(smos.getTarget(), StorageManager.FILETYPE_RELIABLEFILE); 914 ReliableFileOutputStream rfos = (ReliableFileOutputStream) smos.getOutputStream(); 915 File file = rfos.closeIntermediateFile(); sources[idx] = file.getName(); 917 ReliableFile.fileUpdated(new File(getBase(), smos.getTarget())); 918 } else { 919 add(smos.getTarget(), StorageManager.FILETYPE_STANDARD); 920 sources[idx] = outputFile.getName(); 921 } 922 } 923 update(targets, sources); 924 } 925 } 926 } 927 } | Popular Tags |