#57975: Number of file descriptors held by MDR is now limited to 200. javaee5_before_merge7
authormmatula@netbeans.org
Fri, 19 Aug 2005 23:12:57 +0000
changeset 1711362ad48f2e6c
parent 1710 9e4a25755f1a
child 1712 31356a9f1272
#57975: Number of file descriptors held by MDR is now limited to 200.
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/FileCache.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/LogFile.java
     1.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/FileCache.java	Fri Aug 19 14:51:36 2005 +0000
     1.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/FileCache.java	Fri Aug 19 23:12:57 2005 +0000
     1.3 @@ -16,6 +16,7 @@
     1.4  import java.util.*;
     1.5  
     1.6  import org.netbeans.mdr.persistence.*;
     1.7 +import org.netbeans.mdr.util.Logger;
     1.8  
     1.9  /**
    1.10  * FileCache provides transactional cached access to a set of files.
    1.11 @@ -27,9 +28,7 @@
    1.12  */
    1.13  public class FileCache {
    1.14  
    1.15 -    /* files contained in the cache */
    1.16 -    private RandomAccessFile files[];
    1.17 -
    1.18 +    private String[] fileNames;
    1.19      /* sizes of files contained in the cache.  */
    1.20      private int fileSize[];
    1.21  
    1.22 @@ -78,6 +77,42 @@
    1.23      /* A list of objects to notify before comitting */
    1.24      private ArrayList toNotify;
    1.25      
    1.26 +    private static final int MAX_FILES = 200;
    1.27 +    private static final Map OPEN_FILES_CACHE = new LinkedHashMap(MAX_FILES * 2, .5f, true) {
    1.28 +        protected boolean removeEldestEntry(Map.Entry eldest) {
    1.29 +            if (size() > MAX_FILES) {
    1.30 +                RandomAccessFile file = (RandomAccessFile) eldest.getValue();
    1.31 +                try {
    1.32 +                    file.close();
    1.33 +                } catch (IOException e) {
    1.34 +                    Logger.getDefault().notify(e);
    1.35 +                }
    1.36 +                return true;
    1.37 +            }
    1.38 +            return false;
    1.39 +        }
    1.40 +    };
    1.41 +    
    1.42 +    static void closeFile(String fileName) throws IOException {
    1.43 +        RandomAccessFile file;
    1.44 +        synchronized (FileCache.OPEN_FILES_CACHE) {
    1.45 +            file = (RandomAccessFile) FileCache.OPEN_FILES_CACHE.remove(fileName);
    1.46 +        }
    1.47 +        if (file != null) file.close();
    1.48 +    }
    1.49 +
    1.50 +    static RandomAccessFile getFile(String fileName) throws IOException {
    1.51 +        RandomAccessFile result;
    1.52 +        synchronized (FileCache.OPEN_FILES_CACHE) {
    1.53 +            result = (RandomAccessFile) FileCache.OPEN_FILES_CACHE.get(fileName);
    1.54 +            if (result == null) {
    1.55 +                result = new RandomAccessFile(fileName, "rw");
    1.56 +                FileCache.OPEN_FILES_CACHE.put(fileName, result);
    1.57 +            }
    1.58 +        }
    1.59 +        return result;
    1.60 +    }
    1.61 +
    1.62      static {
    1.63          pages = new ArrayList(BtreeDatabase.FILE_CACHE_SIZE);
    1.64          pageHash = new HashMap();
    1.65 @@ -149,16 +184,18 @@
    1.66      public FileCache(String fileNames[], String baseName) 
    1.67              throws StorageException {
    1.68  
    1.69 +        this.fileNames = new String[fileNames.length];
    1.70          boolean failure = true;
    1.71          try {
    1.72              try {
    1.73 -                files = new RandomAccessFile[fileNames.length];
    1.74 +                RandomAccessFile[] files = new RandomAccessFile[fileNames.length];
    1.75                  fileSize = new int[fileNames.length];
    1.76  
    1.77                  FileHeader tmpHeader;
    1.78  
    1.79                  for (int i = 0; i < fileNames.length; i++) {
    1.80 -                    files[i] = new RandomAccessFile(fileNames[i], "rw");
    1.81 +                    files[i] = getFile(fileNames[i]);
    1.82 +                    this.fileNames[i] = fileNames[i];
    1.83                  }
    1.84                  tmpHeader = new FileHeader(files[0]);
    1.85  
    1.86 @@ -187,11 +224,9 @@
    1.87              }
    1.88              finally {
    1.89                  if (failure) {
    1.90 -                    if (files != null) {
    1.91 -                        for (int i = 0; i < files.length; i++) {
    1.92 -                            if (files[i] != null) { 
    1.93 -                                files[i].close();
    1.94 -                            }
    1.95 +                    for (int i = 0; i < this.fileNames.length; i++) {
    1.96 +                        if (this.fileNames[i] != null) { 
    1.97 +                            closeFile(this.fileNames[i]);
    1.98                          }
    1.99                      }
   1.100                      if (log != null)
   1.101 @@ -207,7 +242,15 @@
   1.102  
   1.103      /** return the array of open files
   1.104      */
   1.105 -    RandomAccessFile[] getFiles() {
   1.106 +    RandomAccessFile[] getFiles() throws IOException {
   1.107 +        return getFiles(fileNames);
   1.108 +    }
   1.109 +    
   1.110 +    static RandomAccessFile[] getFiles(String[] fileNames) throws IOException {
   1.111 +        RandomAccessFile[] files = new RandomAccessFile[fileNames.length];
   1.112 +        for (int i = 0; i < fileNames.length; i++) {
   1.113 +            files[i] = FileCache.getFile(fileNames[i]);
   1.114 +        }
   1.115          return files;
   1.116      }
   1.117  
   1.118 @@ -251,8 +294,8 @@
   1.119      /* close all files */
   1.120      private void closeFiles() throws StorageException {
   1.121          try {
   1.122 -            for (int i = 0; i < files.length; i++)
   1.123 -                files[i].close();
   1.124 +            for (int i = 0; i < fileNames.length; i++)
   1.125 +                closeFile(fileNames[i]);
   1.126              log.close();
   1.127          }
   1.128          catch (IOException ex) {
   1.129 @@ -281,7 +324,7 @@
   1.130          if (inXact) {
   1.131  
   1.132              /* update timestaps */
   1.133 -            for (int i = 0; i < files.length; i++) {
   1.134 +            for (int i = 0; i < fileNames.length; i++) {
   1.135                  CachedPage first = getPage(i, 0);
   1.136                  setWritable(first);
   1.137                  FileHeader.updateTime(first, newTimeStamp);
   1.138 @@ -314,7 +357,7 @@
   1.139              
   1.140              if (!instances.contains(owner)) return; // obsolete page from an old cache that was deactivated
   1.141  
   1.142 -            RandomAccessFile file = owner.files[page.key.fileIndex];
   1.143 +            RandomAccessFile file = getFile(owner.fileNames[page.key.fileIndex]);
   1.144              file.seek(page.key.offset);
   1.145              file.write(page.contents);
   1.146              page.isDirty = false;
   1.147 @@ -481,8 +524,9 @@
   1.148          } 
   1.149          else {
   1.150              try {
   1.151 -                instance.files[id.fileIndex].seek(id.offset);
   1.152 -                instance.files[id.fileIndex].readFully(free.contents);
   1.153 +                RandomAccessFile file = getFile(instance.fileNames[id.fileIndex]);
   1.154 +                file.seek(id.offset);
   1.155 +                file.readFully(free.contents);
   1.156              }
   1.157              catch (IOException ex) {
   1.158                  throw new StorageIOException(ex);
   1.159 @@ -508,7 +552,7 @@
   1.160  
   1.161          if (!inXact) { 
   1.162              newTimeStamp = System.currentTimeMillis();
   1.163 -            log.begin(files, header.timeStamp, newTimeStamp);
   1.164 +            log.begin(fileNames, header.timeStamp, newTimeStamp);
   1.165              inXact = true;
   1.166          }
   1.167          log.addPageToLog(page);
   1.168 @@ -532,9 +576,9 @@
   1.169      */
   1.170      public void dumpCache(PrintStream strm) {
   1.171          strm.println("Cached files:");
   1.172 -        for (int i = 0; i < files.length; i++) {
   1.173 +        for (int i = 0; i < fileNames.length; i++) {
   1.174              strm.println(
   1.175 -                Integer.toString(i) + ": " + files[i].toString() +
   1.176 +                Integer.toString(i) + ": " + fileNames[i] +
   1.177                  " size: " + fileSize[i]);
   1.178          }
   1.179          strm.println("");
     2.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/LogFile.java	Fri Aug 19 14:51:36 2005 +0000
     2.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/LogFile.java	Fri Aug 19 23:12:57 2005 +0000
     2.3 @@ -41,8 +41,8 @@
     2.4      /* name of the log file */
     2.5      private final String baseName;
     2.6  
     2.7 -    /* the log file */
     2.8 -    private RandomAccessFile file;
     2.9 +    /* name of the log file */
    2.10 +    private String name;
    2.11  
    2.12      /* bitmaps showing which pages are currently logged */
    2.13      private BitSet pageBitmaps[];
    2.14 @@ -96,14 +96,20 @@
    2.15      }
    2.16  
    2.17      /* create the log file */
    2.18 -    private void createPhysicalLog() throws StorageException {
    2.19 +    private RandomAccessFile createPhysicalLog() throws StorageException {
    2.20 +        String name = BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL);
    2.21 +        RandomAccessFile file = null;
    2.22          try {
    2.23 -            file = new RandomAccessFile(BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL), "rw");
    2.24 +            file = FileCache.getFile(name);
    2.25              file.setLength(0);
    2.26 -            writeMap();
    2.27 -        }
    2.28 -        catch (IOException ex) {
    2.29 +            writeMap(file);
    2.30 +            return file;
    2.31 +        } catch (IOException ex) {
    2.32              throw new StorageIOException(ex);
    2.33 +        } finally {
    2.34 +            if (file != null) {
    2.35 +                this.name = name;
    2.36 +            }
    2.37          }
    2.38      }
    2.39  
    2.40 @@ -120,10 +126,9 @@
    2.41          if (isPageLogged(page))
    2.42              return;
    2.43  
    2.44 -        if (file == null)
    2.45 -            createPhysicalLog();
    2.46 -
    2.47 +        RandomAccessFile file;
    2.48          try {
    2.49 +            file = name == null ? createPhysicalLog() : FileCache.getFile(name);
    2.50              file.seek(currentMap.nextPageOffset());
    2.51              file.write(page.contents);
    2.52          }
    2.53 @@ -142,25 +147,24 @@
    2.54          if (currentMap.isFull()) {
    2.55  
    2.56              // map is full; need to write it
    2.57 -            writeMap();
    2.58 +            writeMap(file);
    2.59          }
    2.60  
    2.61          /* prevent from being written until log is flushed */
    2.62          cache.holdForLog(page);
    2.63      }
    2.64  
    2.65 -
    2.66      /* write the current map page to the log */
    2.67 -    private void writeMap() throws StorageException{
    2.68 -        flushFile();
    2.69 +    private void writeMap(RandomAccessFile file) throws StorageException{
    2.70 +        flushFile(file);
    2.71          currentMap.write(file);
    2.72 -        flushFile();
    2.73 +        flushFile(file);
    2.74          if (currentMap.isFull())
    2.75              currentMap = new MapPage(currentMap);
    2.76      }
    2.77  
    2.78      /* sync the file to disk */
    2.79 -    private void flushFile() throws StorageException{
    2.80 +    private void flushFile(RandomAccessFile file) throws StorageException{
    2.81          try {
    2.82              file.getFD().sync();
    2.83          }
    2.84 @@ -173,8 +177,12 @@
    2.85      * @exception StorageException I/O error writing the log
    2.86      */
    2.87      void flush() throws StorageException{
    2.88 -        writeMap();
    2.89 -        cache.logWasFlushed();
    2.90 +        try {
    2.91 +            writeMap(FileCache.getFile(name));
    2.92 +            cache.logWasFlushed();
    2.93 +        } catch (IOException e) {
    2.94 +            throw new StorageIOException(e);
    2.95 +        }
    2.96      }
    2.97  
    2.98      /** begin a new transaction
    2.99 @@ -183,11 +191,17 @@
   2.100      * @param long newTimeStamp the timestamp for the new transaction
   2.101      * @exception StorageException I/O error accessing the files
   2.102      */
   2.103 -    void begin(RandomAccessFile files[], long timeStamp, long newTimeStamp) 
   2.104 +    void begin(String fileNames[], long timeStamp, long newTimeStamp) 
   2.105                  throws StorageException {
   2.106  
   2.107 -        file = null;
   2.108 +        name = null;
   2.109          currentMap = new MapPage(pageSize, numFiles, 0);
   2.110 +        RandomAccessFile files[];
   2.111 +        try {
   2.112 +            files = FileCache.getFiles(fileNames);
   2.113 +        } catch (IOException e) {
   2.114 +            throw new StorageIOException(e);
   2.115 +        }
   2.116          currentMap.setEOFs(files);
   2.117          for (int i = 0; i < numFiles; i++) {
   2.118              pageBitmaps[i].xor(pageBitmaps[i]);
   2.119 @@ -201,15 +215,15 @@
   2.120      */
   2.121      void commit() throws StorageException{
   2.122          try {
   2.123 -            if (file != null) {
   2.124 -                file.close();
   2.125 -                (new File(BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL))).delete();
   2.126 +            if (name != null) {
   2.127 +                FileCache.closeFile(name);
   2.128 +                new File(name).delete();
   2.129              }
   2.130          }
   2.131          catch (IOException ex) {
   2.132              throw new StorageIOException(ex);
   2.133          }
   2.134 -        file = null;
   2.135 +        name = null;
   2.136          afterCommitFailure = 
   2.137              cache.checkForForcedFailure(
   2.138          "org.netbeans.mdr.persistence.btreeimpl.btreestorage.LogFile.afterCommitFailure", 
   2.139 @@ -221,10 +235,10 @@
   2.140      */
   2.141      void close() throws StorageException{
   2.142          try {
   2.143 -            if (file != null)
   2.144 -                file.close();
   2.145 +            if (name != null) {
   2.146 +                FileCache.closeFile(name);
   2.147          }
   2.148 -        catch (IOException ex) {
   2.149 +        } catch (IOException ex) {
   2.150              throw new StorageIOException(ex);
   2.151          }
   2.152      }
   2.153 @@ -248,7 +262,6 @@
   2.154              try {
   2.155                  logFile = new RandomAccessFile(BtreeDatabase.getFileName(baseName, BtreeDatabase.LFL), "r");
   2.156                  files = cache.getFiles();
   2.157 -
   2.158                  if (files.length != numFiles) {
   2.159                      throw new StorageBadRequestException(
   2.160                          MessageFormat.format(