You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FlatFileCacheBacking.java 5.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* *******************************************************************
  2. * Copyright (c) 2012 VMware, Inc. custard
  3. *
  4. * All rights reserved.
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Public License v1.0
  7. * which accompanies this distribution and is available at
  8. * http://www.eclipse.org/legal/epl-v10.html
  9. *
  10. * Contributors:
  11. * Lyor Goldstein
  12. * ******************************************************************/
  13. package org.aspectj.weaver.tools.cache;
  14. import java.io.File;
  15. import java.io.FileOutputStream;
  16. import java.io.IOException;
  17. import java.io.StreamCorruptedException;
  18. import java.util.Map;
  19. import java.util.TreeMap;
  20. import org.aspectj.util.FileUtil;
  21. import org.aspectj.util.LangUtil;
  22. /**
  23. * Uses a "flat" files model to store the cached instrumented classes
  24. * and aspects - i.e., each class/aspect is stored as a <U>separate</U> (binary)
  25. * file. This is a good mechanism when the number of instrumented class is
  26. * relatively small (a few 10's). The reason for it is that scanning a folder
  27. * that has many files in it quickly becomes an I/O bottleneck. Also, some
  28. * O/S-es may impose internal limits on the maximum number of &quot;children&quot;
  29. * a folder node may have. On the other hand, it is much faster (again, for
  30. * small number of instrumented classes) than the ZIP cache since each class/aspect
  31. * is represented by a single file - thus adding/removing/modifying it is easier.
  32. *
  33. * @author Lyor Goldstein
  34. */
  35. public class FlatFileCacheBacking extends AsynchronousFileCacheBacking {
  36. private static final AsynchronousFileCacheBackingCreator<FlatFileCacheBacking> defaultCreator=
  37. new AsynchronousFileCacheBackingCreator<FlatFileCacheBacking>() {
  38. public FlatFileCacheBacking create(File cacheDir) {
  39. return new FlatFileCacheBacking(cacheDir);
  40. }
  41. };
  42. public FlatFileCacheBacking(File cacheDir) {
  43. super(cacheDir);
  44. }
  45. public static final FlatFileCacheBacking createBacking (File cacheDir) {
  46. return createBacking(cacheDir, defaultCreator);
  47. }
  48. @Override
  49. protected Map<String, byte[]> readClassBytes(Map<String, IndexEntry> indexMap, File cacheDir) {
  50. return readClassBytes(indexMap, cacheDir.listFiles());
  51. }
  52. protected Map<String, byte[]> readClassBytes (Map<String,IndexEntry> indexMap, File[] files) {
  53. Map<String, byte[]> result= new TreeMap<>();
  54. if (LangUtil.isEmpty(files)) {
  55. return result;
  56. }
  57. for (File file : files) {
  58. if (!file.isFile()) {
  59. continue; // skip sub-directories - we expect flat files
  60. }
  61. String key=file.getName();
  62. if (INDEX_FILE.equalsIgnoreCase(key)) {
  63. continue; // skip the index itself if found
  64. }
  65. IndexEntry entry=indexMap.get(key);
  66. if ((entry == null) || entry.ignored) { // if not in index or ignored then remove it
  67. if ((logger != null) && logger.isTraceEnabled()) {
  68. logger.info("readClassBytes(" + key + ") remove orphan/ignored: " + file.getAbsolutePath());
  69. }
  70. FileUtil.deleteContents(file);
  71. continue;
  72. }
  73. try {
  74. byte[] bytes=FileUtil.readAsByteArray(file);
  75. long crc=crc(bytes);
  76. if (crc != entry.crcWeaved) {
  77. throw new StreamCorruptedException("Mismatched CRC - expected=" + entry.crcWeaved + "/got=" + crc);
  78. }
  79. result.put(key, bytes);
  80. if ((logger != null) && logger.isTraceEnabled()) {
  81. logger.debug("readClassBytes(" + key + ") cached from " + file.getAbsolutePath());
  82. }
  83. } catch(IOException e) {
  84. if ((logger != null) && logger.isTraceEnabled()) {
  85. logger.error("Failed (" + e.getClass().getSimpleName() + ")"
  86. + " to read bytes from " + file.getAbsolutePath()
  87. + ": " + e.getMessage());
  88. }
  89. indexMap.remove(key); // no need for the entry if no file - force a re-write of its bytes
  90. FileUtil.deleteContents(file); // assume some kind of corruption
  91. continue;
  92. }
  93. }
  94. return result;
  95. }
  96. @Override
  97. protected IndexEntry resolveIndexMapEntry (File cacheDir, IndexEntry ie) {
  98. File cacheEntry = new File(cacheDir, ie.key);
  99. if (ie.ignored || cacheEntry.canRead()) {
  100. return ie;
  101. } else {
  102. return null;
  103. }
  104. }
  105. @Override
  106. protected void writeClassBytes (String key, byte[] bytes) throws Exception {
  107. File dir=getCacheDirectory(), file=new File(dir, key);
  108. FileOutputStream out=new FileOutputStream(file);
  109. try {
  110. out.write(bytes);
  111. } finally {
  112. out.close();
  113. }
  114. }
  115. @Override
  116. protected void removeClassBytes (String key) throws Exception {
  117. File dir=getCacheDirectory(), file=new File(dir, key);
  118. if (file.exists() && (!file.delete())) {
  119. throw new StreamCorruptedException("Failed to delete " + file.getAbsolutePath());
  120. }
  121. }
  122. }