Heap usage significantly improved. Caches are now static rather than per storage file. BLD200408301800
authormmatula@netbeans.org
Mon, 30 Aug 2004 16:57:50 +0000
changeset 157256273b1a3b48
parent 1571 d19b8d561304
child 1573 ece28e93af29
Heap usage significantly improved. Caches are now static rather than per storage file.
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/IntInfo.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/MOFIDInfo.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/StringInfo.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeDatabase.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeFactory.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeStorage.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/CachedPage.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/FileCache.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/MDRCache.java
mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/TransactionCache.java
     1.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/IntInfo.java	Mon Aug 23 08:51:22 2004 +0000
     1.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/IntInfo.java	Mon Aug 30 16:57:50 2004 +0000
     1.3 @@ -21,8 +21,7 @@
     1.4  public class IntInfo extends EntryTypeInfo {
     1.5  
     1.6      public String typeName() {
     1.7 -
     1.8 -        return new String("Integer");
     1.9 +        return "Integer";
    1.10      }
    1.11  
    1.12      /**
     2.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/MOFIDInfo.java	Mon Aug 23 08:51:22 2004 +0000
     2.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/MOFIDInfo.java	Mon Aug 30 16:57:50 2004 +0000
     2.3 @@ -33,7 +33,7 @@
     2.4      }
     2.5          
     2.6      public String typeName() {
     2.7 -        return new String("MOFID");
     2.8 +        return "MOFID";
     2.9      }
    2.10  
    2.11      /**
     3.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/StringInfo.java	Mon Aug 23 08:51:22 2004 +0000
     3.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreeindex/StringInfo.java	Mon Aug 30 16:57:50 2004 +0000
     3.3 @@ -21,8 +21,7 @@
     3.4  
     3.5  public class StringInfo extends EntryTypeInfo {
     3.6      public String typeName() {
     3.7 -
     3.8 -        return new String("String");
     3.9 +        return "String";
    3.10      }
    3.11  
    3.12      public byte[] toBuffer(Object object) {
     4.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeDatabase.java	Mon Aug 23 08:51:22 2004 +0000
     4.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeDatabase.java	Mon Aug 30 16:57:50 2004 +0000
     4.3 @@ -69,7 +69,7 @@
     4.4  
     4.5      /* tuning parameters explained above */
     4.6      static final int PAGE_SIZE = 2048;
     4.7 -    static final int FILE_CACHE_SIZE = 64;
     4.8 +    static final int FILE_CACHE_SIZE = 128;
     4.9      static final int MDR_CACHE_SIZE = 2048;
    4.10      static final int MDR_CACHE_THRESHHOLD = 1000;
    4.11  
    4.12 @@ -220,7 +220,7 @@
    4.13      }
    4.14      
    4.15      private int getIntProperty(String propertyName, int defaultValue) {
    4.16 -        String value = myStorage.getProperty(propertyName);
    4.17 +        String value = (String) myStorage.getProperty(propertyName);
    4.18          int result = defaultValue;
    4.19          if (value != null) {
    4.20              try {
    4.21 @@ -236,7 +236,7 @@
    4.22      private void open(boolean isNew) throws StorageException {
    4.23      	boolean rebuildIndex = false;
    4.24  
    4.25 -        cache = new MDRCache(getIntProperty(BtreeFactory.CACHE_SIZE, MDR_CACHE_SIZE), this, getIntProperty(BtreeFactory.CACHE_THRESHHOLD, MDR_CACHE_THRESHHOLD));        
    4.26 +        cache = new MDRCache(getIntProperty(BtreeFactory.CACHE_SIZE, MDR_CACHE_SIZE), this, getIntProperty(BtreeFactory.CACHE_THRESHHOLD, MDR_CACHE_THRESHHOLD), (Map) myStorage.getProperty(BtreeFactory.CACHE_INSTANCE));
    4.27          transactionCache = new TransactionCache ();
    4.28  	String names[] = getFileNames(repositoryName);
    4.29  
    4.30 @@ -268,8 +268,7 @@
    4.31  	    }
    4.32  	}
    4.33  
    4.34 -        fileCache = new FileCache(
    4.35 -                        PAGE_SIZE, FILE_CACHE_SIZE, fileNames, names[LFL]);
    4.36 +        fileCache = new FileCache(fileNames, names[LFL]);
    4.37          boolean failure = true;
    4.38          try {
    4.39              dataFile = new BtreeDataFile(this.myStorage, fileCache, 0);
    4.40 @@ -323,8 +322,7 @@
    4.41  
    4.42  	BtreeDataFile.create( this.myStorage, copyNames[DFL], new FileHeader(), PAGE_SIZE, false);
    4.43  	try {
    4.44 -	    copyCache = new FileCache(
    4.45 -                        PAGE_SIZE, FILE_CACHE_SIZE, fileNames, copyNames[LFL]);
    4.46 +	    copyCache = new FileCache(fileNames, copyNames[LFL]);
    4.47  	    copyFile = new BtreeDataFile(this.myStorage, copyCache, 0);
    4.48  	    dataFile.copy(copyFile);
    4.49  	    copyCache.commit();
    4.50 @@ -438,6 +436,7 @@
    4.51          
    4.52          if (transactionCache.tresholdReached ()) {            
    4.53              try {
    4.54 +                //System.err.println("Threshhold reached!");
    4.55                  fileCache.commit();
    4.56                  transactionCache.clear ();
    4.57              } catch (StorageException ex) {	    
    4.58 @@ -550,7 +549,9 @@
    4.59  	    // Record that commit has failed.
    4.60  	    saveFailed = true;
    4.61  	    throw(ex);
    4.62 -	}
    4.63 +	} finally {
    4.64 +            cache.updateSize();
    4.65 +        }
    4.66      }
    4.67  
    4.68      /** roll back all changes 
     5.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeFactory.java	Mon Aug 23 08:51:22 2004 +0000
     5.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeFactory.java	Mon Aug 30 16:57:50 2004 +0000
     5.3 @@ -24,6 +24,7 @@
     5.4      public static final String STORAGE_FILE_NAME = "org.netbeans.mdr.persistence.btreeimpl.filename";       // NOI18N
     5.5      public static final String CACHE_SIZE = "org.netbeans.mdr.persistence.btreeimpl.cacheSize"; // NOI18N
     5.6      public static final String CACHE_THRESHHOLD = "org.netbeans.mdr.persistence.btreeimpl.cacheThreshHold"; // NOI18N
     5.7 +    public static final String CACHE_INSTANCE = "org.netbeans.mdr.persistence.btreeimpl.cacheInstance"; // NOI18N
     5.8      public static final String STORAGE_UUID = "org.netbeans.mdr.persistence.btreeimpl.uuid";       // NOI18N
     5.9      
    5.10      // Btree MOFID constnants
     6.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeStorage.java	Mon Aug 23 08:51:22 2004 +0000
     6.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/BtreeStorage.java	Mon Aug 30 16:57:50 2004 +0000
     6.3 @@ -86,8 +86,8 @@
     6.4          
     6.5      }
     6.6      
     6.7 -    String getProperty(String name) {
     6.8 -        return (String) properties.get(name);
     6.9 +    Object getProperty(String name) {
    6.10 +        return properties.get(name);
    6.11      }
    6.12      
    6.13      /** Return our name
     7.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/CachedPage.java	Mon Aug 23 08:51:22 2004 +0000
     7.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/CachedPage.java	Mon Aug 30 16:57:50 2004 +0000
     7.3 @@ -24,7 +24,7 @@
     7.4      /** Description of which page this is */
     7.5      PageID key;
     7.6      /** How many times this page has been pinned and not unpinned */
     7.7 -    int pinCount;
     7.8 +    private int pinCount;
     7.9      /** true if this page has been modified */
    7.10      boolean isDirty;
    7.11      /** true if the log file must be flushed before this page can be written */
    7.12 @@ -39,14 +39,18 @@
    7.13      /** create a page of the specified size 
    7.14      * @param size the page size for the cache
    7.15      */
    7.16 -    CachedPage(int size, FileCache cache) {
    7.17 +    CachedPage(int size) {
    7.18          key = null;
    7.19          pinCount = 0;
    7.20          isDirty = false;
    7.21          heldForLog = false;
    7.22 -        owner = cache;
    7.23 +        owner = null;
    7.24          contents = new byte[size];
    7.25      }
    7.26 +    
    7.27 +    public FileCache getOwner() {
    7.28 +        return owner;
    7.29 +    }
    7.30  
    7.31      /** Make this page writable.  If it was not writable previously,
    7.32      * this causes it to be logged.  This must be called before the page
    7.33 @@ -61,12 +65,28 @@
    7.34      /** reinitialize thie object to point to a different file page 
    7.35      * @param id the file and page number this will become
    7.36      */
    7.37 -    void reInit(PageID id) {
    7.38 +    void reInit(FileCache owner, PageID id) {
    7.39 +        this.owner = owner;
    7.40          key = id;
    7.41          pinCount = 0;
    7.42          isDirty = false;
    7.43          heldForLog = false;
    7.44      }
    7.45 +    
    7.46 +    public int pin(FileCache owner) {
    7.47 +        assert pinCount == 0 || this.owner == owner;
    7.48 +        this.owner = owner;
    7.49 +        return pinCount++;
    7.50 +    }
    7.51 +    
    7.52 +    public int getPinCount() {
    7.53 +        return pinCount;
    7.54 +    }
    7.55 +    
    7.56 +    public int innerUnpin() {
    7.57 +        pinCount--;
    7.58 +        return pinCount;
    7.59 +    }
    7.60          
    7.61      /** client calls this when it is done with the page */
    7.62      public void unpin() throws StorageException {
     8.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/FileCache.java	Mon Aug 23 08:51:22 2004 +0000
     8.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/FileCache.java	Mon Aug 30 16:57:50 2004 +0000
     8.3 @@ -42,20 +42,23 @@
     8.4      /* our log file */
     8.5      private LogFile log;
     8.6  
     8.7 -    /* size of cached pages */
     8.8 -    private int pageSize;
     8.9 -
    8.10      /* true if cache has uncomitted changes */
    8.11      private boolean inXact;
    8.12  
    8.13 +    /* size of cached pages */
    8.14 +    private static int pageSize;
    8.15 +
    8.16      /* all pages */
    8.17 -    private ArrayList pages;
    8.18 +    private static ArrayList pages;
    8.19  
    8.20      /* pages hashed by their ID */
    8.21 -    private HashMap pageHash;
    8.22 +    private static HashMap pageHash;
    8.23  
    8.24      /* pages not curently pinned */
    8.25 -    private IntrusiveList freePages;
    8.26 +    private static IntrusiveList freePages;
    8.27 +    
    8.28 +    private static HashSet/*<FileCache>*/ instances = new HashSet();
    8.29 +    
    8.30  
    8.31      /* dirty pages which cannot be written until the log is flushed */
    8.32      private HashMap heldForLog;
    8.33 @@ -64,21 +67,29 @@
    8.34      private long newTimeStamp;
    8.35  
    8.36      /* caching stats */
    8.37 -    private int hits = 0;
    8.38 -    private int misses = 0;
    8.39 -    private int pagesFlushed = 0;
    8.40 +    private static int hits = 0;
    8.41 +    private static int misses = 0;
    8.42 +    private static int extensions = 0;
    8.43 +    private static int pagesFlushed = 0;
    8.44 +
    8.45      private int logFlushes = 0;
    8.46 -    private int extensions = 0;
    8.47 -
    8.48  
    8.49      /* for regression testing */
    8.50 -    private int flushFailure = -1;  /* fail after this many flushes */
    8.51 -    private int commitFailure = -1; /* fail after this many commits */
    8.52 +    private static int flushFailure = -1;  /* fail after this many flushes */
    8.53 +    private static int commitFailure = -1; /* fail after this many commits */
    8.54  
    8.55      /* A list of objects to notify before comitting */
    8.56      private ArrayList toNotify;
    8.57 +    
    8.58 +    static {
    8.59 +        pages = new ArrayList(BtreeDatabase.FILE_CACHE_SIZE);
    8.60 +        pageHash = new HashMap();
    8.61 +        freePages = new IntrusiveList();
    8.62 +        pageSize = BtreeDatabase.PAGE_SIZE;
    8.63 +        addPages(BtreeDatabase.FILE_CACHE_SIZE);
    8.64 +    }
    8.65  
    8.66 -    int checkForForcedFailure(String property, int count) {
    8.67 +    static int checkForForcedFailure(String property, int count) {
    8.68          if (count == -1) {
    8.69              /* see if we're supposed to fail after N operations */
    8.70              Integer failCount = Integer.getInteger(property);
    8.71 @@ -94,9 +105,9 @@
    8.72      }
    8.73  
    8.74      /* extend the cache */
    8.75 -    private void addPages(int numToAdd) {
    8.76 +    private static void addPages(int numToAdd) {
    8.77          for (int i = 0; i < numToAdd; i++) {
    8.78 -            CachedPage page = new CachedPage(pageSize, this);
    8.79 +            CachedPage page = new CachedPage(pageSize);
    8.80              pages.add(page);
    8.81              freePages.addLast(page);
    8.82          }
    8.83 @@ -120,7 +131,7 @@
    8.84          while (itr.hasNext()) {
    8.85              CachedPage page = (CachedPage)itr.next();
    8.86              page.heldForLog = false;
    8.87 -            if (page.pinCount == 0)
    8.88 +            if (page.getPinCount() == 0)
    8.89                  freePages.addFirst(page);
    8.90          }
    8.91          heldForLog.clear();
    8.92 @@ -138,8 +149,7 @@
    8.93      * headers, or the log file exists but is not consistent with the files
    8.94      * @exception ConsistencyException if the log file exists and is corrupted
    8.95      */
    8.96 -    public FileCache(
    8.97 -        int pgSize, int numBufs, String names[], String logName) 
    8.98 +    public FileCache(String names[], String logName) 
    8.99              throws StorageException {
   8.100  
   8.101          boolean failure = true;
   8.102 @@ -157,9 +167,8 @@
   8.103                  }
   8.104                  tmpHeader = new FileHeader(files[0]);
   8.105  
   8.106 -                pageSize = pgSize;
   8.107                  log = new LogFile(
   8.108 -                    this, logName, pageSize, fileNames.length, tmpHeader.fileId);
   8.109 +                    this, logName, BtreeDatabase.PAGE_SIZE, fileNames.length, tmpHeader.fileId);
   8.110  
   8.111                  for (int i = 0; i < fileNames.length; i++) {
   8.112                      fileSize[i] = (int)files[i].length();
   8.113 @@ -177,13 +186,9 @@
   8.114                      }
   8.115                  }
   8.116  
   8.117 -                pages = new ArrayList(numBufs);
   8.118 -                pageHash = new HashMap();
   8.119                  heldForLog = new HashMap();
   8.120 -                freePages = new IntrusiveList();
   8.121 -                addPages(numBufs);
   8.122 -
   8.123                  failure = false;
   8.124 +                instances.add(this);
   8.125              }
   8.126              finally {
   8.127                  if (failure) {
   8.128 @@ -235,6 +240,8 @@
   8.129          }
   8.130          catch (IOException ex) {
   8.131              throw new StorageIOException(ex);
   8.132 +        } finally {
   8.133 +            instances.remove(this);
   8.134          }
   8.135      }
   8.136  
   8.137 @@ -269,7 +276,7 @@
   8.138              Iterator itr = pages.iterator();
   8.139              while (itr.hasNext()) {
   8.140                  CachedPage page = (CachedPage)itr.next();
   8.141 -                if (page.isDirty)
   8.142 +                if (page.isDirty && page.getOwner() == this)
   8.143                      flushOne(page);
   8.144              }
   8.145              log.commit();
   8.146 @@ -280,18 +287,20 @@
   8.147  
   8.148          
   8.149      /* write a dirty page to the disk */
   8.150 -    private void flushOne(CachedPage page) throws StorageException{
   8.151 +    private static void flushOne(CachedPage page) throws StorageException{
   8.152          try {
   8.153              flushFailure = checkForForcedFailure(
   8.154                  "org.netbeans.mdr.persistence.btreeimpl.btreestorage.FileCache.flushFailure", 
   8.155                  flushFailure);
   8.156 -            RandomAccessFile file = files[page.key.fileIndex];
   8.157 +            FileCache owner = page.getOwner();
   8.158 +            assert owner != null;
   8.159 +            RandomAccessFile file = owner.files[page.key.fileIndex];
   8.160              file.seek(page.key.offset);
   8.161              file.write(page.contents);
   8.162              page.isDirty = false;
   8.163              pagesFlushed++;
   8.164 -            if (page.key.offset >= fileSize[page.key.fileIndex]) {
   8.165 -                fileSize[page.key.fileIndex] = page.key.offset + pageSize;
   8.166 +            if (page.key.offset >= owner.fileSize[page.key.fileIndex]) {
   8.167 +                owner.fileSize[page.key.fileIndex] = page.key.offset + pageSize;
   8.168              }
   8.169          }
   8.170          catch (IOException ex) {
   8.171 @@ -317,12 +326,12 @@
   8.172      */
   8.173      public synchronized void unpin(CachedPage page) 
   8.174                          throws StorageException {
   8.175 -        if (page.pinCount <= 0) {
   8.176 +        if (page.getPinCount() <= 0) {
   8.177              throw new StorageTransientDataException(
   8.178                          "Attempt to unpin page which is not pinned");
   8.179          }
   8.180  
   8.181 -        if ((--page.pinCount == 0) && !page.heldForLog) {
   8.182 +        if ((page.innerUnpin() == 0) && !page.heldForLog) {
   8.183              freePages.addFirst(page);
   8.184          }
   8.185  
   8.186 @@ -343,7 +352,7 @@
   8.187          CachedPage retval[] = new CachedPage[size];
   8.188          for (int i = 0 ; i < size; i++) {
   8.189              retval[i] = 
   8.190 -                getPage(new PageID(fileidx, pageSize * (first + i)), false);
   8.191 +                getPage(this, new PageID(fileidx, pageSize * (first + i)), false);
   8.192          }
   8.193  
   8.194          return retval;
   8.195 @@ -359,7 +368,7 @@
   8.196      */
   8.197      public synchronized CachedPage getPage(int fileidx, int pageNum) 
   8.198                                                      throws StorageException {
   8.199 -        return getPage(new PageID(fileidx, pageNum * pageSize), false);
   8.200 +        return getPage(this, new PageID(fileidx, pageNum * pageSize), false);
   8.201      }
   8.202  
   8.203      /** Get the single page at the desired offset into the file
   8.204 @@ -370,7 +379,25 @@
   8.205      * @exception StorageException I/O error reading the page
   8.206      */
   8.207      synchronized CachedPage getPage(PageID page) throws StorageException {
   8.208 -        return getPage(page, false);
   8.209 +        return getPage(this, page, false);
   8.210 +    }
   8.211 +    
   8.212 +    private static class HashKey {
   8.213 +        public final FileCache owner;
   8.214 +        public final PageID id;
   8.215 +        
   8.216 +        public HashKey(FileCache owner, PageID id) {
   8.217 +            this.owner = owner;
   8.218 +            this.id = id;
   8.219 +        }
   8.220 +        
   8.221 +        public boolean equals(Object o) {
   8.222 +            return o == this || ((o instanceof HashKey) && (((HashKey) o).owner == owner) && (((HashKey) o).id.equals(id)));
   8.223 +        }
   8.224 +        
   8.225 +        public int hashCode() {
   8.226 +            return owner.hashCode() + 31 * id.hashCode();
   8.227 +        }
   8.228      }
   8.229  
   8.230      /** Get the single page at the desired offset into the file
   8.231 @@ -381,12 +408,13 @@
   8.232      * @return the page requested
   8.233      * @exception StorageException I/O error reading the page
   8.234      */
   8.235 -    private CachedPage getPage(PageID id, boolean fromCacheOnly) 
   8.236 +    private static CachedPage getPage(FileCache instance, PageID id, boolean fromCacheOnly) 
   8.237              throws StorageException {
   8.238 -        CachedPage page = (CachedPage)pageHash.get(id);
   8.239 +        HashKey key = new HashKey(instance, id);
   8.240 +        CachedPage page = (CachedPage)pageHash.get(key);
   8.241          if (page != null)
   8.242          {
   8.243 -            if (page.pinCount++ == 0 && !page.heldForLog)
   8.244 +            if (page.pin(instance) == 0 && !page.heldForLog)
   8.245                  freePages.remove(page);
   8.246              hits++;
   8.247              return page;
   8.248 @@ -399,12 +427,15 @@
   8.249          CachedPage free = (CachedPage)freePages.removeLast();
   8.250          if (free == null) {
   8.251              /* if there are any waiting for the log to be flushed, flush it */
   8.252 -            if (!heldForLog.isEmpty())
   8.253 -            {
   8.254 -                log.flush();
   8.255 -                logFlushes++;
   8.256 -                free = (CachedPage)freePages.removeLast();
   8.257 +            for (Iterator it = instances.iterator(); it.hasNext();) {
   8.258 +                FileCache cache = (FileCache) it.next();
   8.259 +                if (!cache.heldForLog.isEmpty())
   8.260 +                {
   8.261 +                    cache.log.flush();
   8.262 +                    cache.logFlushes++;
   8.263 +                }
   8.264              }
   8.265 +            free = (CachedPage)freePages.removeLast();
   8.266          }
   8.267  
   8.268          if (free == null) {
   8.269 @@ -419,26 +450,26 @@
   8.270              flushOne(free);
   8.271          }
   8.272              
   8.273 -        if (free.key != null) {
   8.274 -            pageHash.remove(free.key);
   8.275 +        if (free.key != null && free.getOwner() != null) {
   8.276 +            pageHash.remove(new HashKey(free.getOwner(), free.key));
   8.277          }
   8.278  
   8.279 -        free.reInit(id);
   8.280 -        pageHash.put(id, free);
   8.281 -        if (id.offset >= fileSize[id.fileIndex]) {
   8.282 +        free.reInit(instance, id);
   8.283 +        pageHash.put(key, free);
   8.284 +        if (id.offset >= instance.fileSize[id.fileIndex]) {
   8.285              Arrays.fill(free.contents, (byte)0);
   8.286          } 
   8.287          else {
   8.288              try {
   8.289 -                files[id.fileIndex].seek(id.offset);
   8.290 -                files[id.fileIndex].readFully(free.contents);
   8.291 +                instance.files[id.fileIndex].seek(id.offset);
   8.292 +                instance.files[id.fileIndex].readFully(free.contents);
   8.293              }
   8.294              catch (IOException ex) {
   8.295                  throw new StorageIOException(ex);
   8.296              }
   8.297          }
   8.298  
   8.299 -        free.pinCount = 1;
   8.300 +        free.pin(instance);
   8.301          misses++;
   8.302          return free;
   8.303      }
   8.304 @@ -514,7 +545,7 @@
   8.305  	int held = 0;
   8.306  	for (int i = 0; i < pages.size(); i++) {
   8.307  	    CachedPage pg = (CachedPage)pages.get(i);
   8.308 -	    if (pg.pinCount > 0) {
   8.309 +	    if (pg.getPinCount() > 0) {
   8.310  	    	pinned++;
   8.311  //		strm.println("Pinned page "+ pg.key + " count: " + pg.pinCount);
   8.312  	    }
     9.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/MDRCache.java	Mon Aug 23 08:51:22 2004 +0000
     9.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/MDRCache.java	Mon Aug 30 16:57:50 2004 +0000
     9.3 @@ -46,13 +46,13 @@
     9.4  */
     9.5  
     9.6  public class MDRCache {
     9.7 +    private static final ArrayList instances = new ArrayList();
     9.8  
     9.9      /* hash MOF ID's to references */
    9.10 -    private HashMap hashOnId;
    9.11 +    private final FacilityCache hashOnId;
    9.12  
    9.13      /* Hard references */
    9.14 -    //private Object hardRef[];
    9.15 -    private CacheReference hardRef[];
    9.16 +    private final Map hardRef;
    9.17  
    9.18      /* current slot in above index */
    9.19      private int hardIndex;
    9.20 @@ -73,7 +73,15 @@
    9.21      OverflowHandler handler;
    9.22  
    9.23      /* our threshhold for changed objects */
    9.24 -    int threshhold;
    9.25 +    private static final int threshhold = Integer.getInteger(
    9.26 +	    "org.netbeans.mdr.persistence.btreeimpl.btreestorage.MDRCache.threshhold", 
    9.27 +	    BtreeDatabase.MDR_CACHE_THRESHHOLD).intValue() * 2;
    9.28 +    private static final int LOCAL_MINIMUM = 200;
    9.29 +    private static int size = 0;
    9.30 +    
    9.31 +    private int localThreshhold;
    9.32 +    private int lastLocalSize = 0;
    9.33 +    
    9.34  
    9.35      /* caching statistics */
    9.36      int hits;
    9.37 @@ -85,25 +93,93 @@
    9.38      * @param hndlr handler to call when the cache has too many changed objects
    9.39      * @param limit number of changed objects to allow
    9.40      */
    9.41 -    public MDRCache(int size, OverflowHandler hndlr, int limit) {
    9.42 -    	this(size);
    9.43 +    public MDRCache(int size, OverflowHandler hndlr, int limit, Map hardRef) {
    9.44 +    	this(size, hardRef);
    9.45  	handler = hndlr;
    9.46 -	threshhold = Integer.getInteger(
    9.47 -	    "org.netbeans.mdr.persistence.btreeimpl.btreestorage.MDRCache.threshhold", 
    9.48 -	    limit).intValue();
    9.49 +        localThreshhold = limit;
    9.50 +    }
    9.51 +
    9.52 +    private static class CacheClass implements Map {
    9.53 +        private final Object inner[] = new Object[256];
    9.54 +        private int size, cursor;
    9.55 +        
    9.56 +        public Set keySet() {
    9.57 +            throw new UnsupportedOperationException();
    9.58 +        }
    9.59 +
    9.60 +        public Set entrySet() {
    9.61 +            throw new UnsupportedOperationException();
    9.62 +        }
    9.63 +
    9.64 +        public void putAll(Map t) {
    9.65 +            throw new UnsupportedOperationException();
    9.66 +        }
    9.67 +
    9.68 +        public boolean isEmpty() {
    9.69 +            return size == 0;
    9.70 +        }
    9.71 +
    9.72 +        public boolean containsKey(Object key) {
    9.73 +            throw new UnsupportedOperationException();
    9.74 +        }
    9.75 +
    9.76 +        public boolean containsValue(Object value) {
    9.77 +            throw new UnsupportedOperationException();
    9.78 +        }
    9.79 +
    9.80 +        public Collection values() {
    9.81 +            throw new UnsupportedOperationException();
    9.82 +        }
    9.83 +
    9.84 +        public Object put(Object key, Object value) {
    9.85 +            inner[cursor] = value;
    9.86 +            cursor++;
    9.87 +            if (size < inner.length) {
    9.88 +                size++;
    9.89 +            }
    9.90 +            if (cursor >= size) {
    9.91 +                cursor = 0;
    9.92 +            }
    9.93 +            return null;
    9.94 +        }
    9.95 +
    9.96 +        public void clear() {
    9.97 +            Arrays.fill(inner, null);
    9.98 +            size = 0;
    9.99 +            cursor = 0;
   9.100 +        }
   9.101 +
   9.102 +        public int size() {
   9.103 +            return size;
   9.104 +        }
   9.105 +
   9.106 +        public Object get(Object key) {
   9.107 +            throw new UnsupportedOperationException();
   9.108 +        }
   9.109 +
   9.110 +        public Object remove(Object key) {
   9.111 +            throw new UnsupportedOperationException();
   9.112 +        }
   9.113      }
   9.114  
   9.115      /** Create the cache
   9.116      * @param size how many objects to cache in memory */
   9.117 -    public MDRCache(int size) {
   9.118 -        hashOnId = new HashMap();
   9.119 +    public MDRCache(final int size, Map hardRef) {
   9.120 +        hashOnId = new FacilityCache();
   9.121 +        if (hardRef == null) {
   9.122 +            hardRef = new CacheClass()/*LinkedHashMap(2 * size, 0.5f, true) {
   9.123 +                public boolean removeEldestEntry(Map.Entry entry) {
   9.124 +                    return size() < size;
   9.125 +                }
   9.126 +            }*/;
   9.127 +        }
   9.128 +        this.hardRef = hardRef;
   9.129          deleted = new HashMap();
   9.130 -        //hardRef = new Object[size];
   9.131 -        hardRef = new CacheReference[size];
   9.132 -        hardIndex = 0;
   9.133 -        queue = new ReferenceQueue();
   9.134          dirty = new HashMap();
   9.135          newOnes = new HashMap();
   9.136 +        synchronized (MDRCache.class) {
   9.137 +            instances.add(this);
   9.138 +        }
   9.139      }
   9.140  
   9.141      /** returns true if the cache contains any changed objects
   9.142 @@ -119,42 +195,27 @@
   9.143      * @param o the object to add
   9.144      */
   9.145      public synchronized void put(Object m, Object o) throws StorageException {
   9.146 -        CacheReference cr = new CacheReference(m, o, queue);
   9.147 -        CacheReference oldCr = (CacheReference)hashOnId.put(m, cr);
   9.148 -        //cr.inCache = true;
   9.149 -        if (oldCr != null) {
   9.150 -            //oldCr.inCache = false;
   9.151 -            if (oldCr.get() != null && oldCr.get() != o) {
   9.152 -                throw new StorageBadRequestException(
   9.153 -                    MessageFormat.format("Duplicate MOF ID: {0}",
   9.154 -                                         new Object[] {m} ));
   9.155 -            }
   9.156 -            oldCr.clear();
   9.157 +        if (hashOnId.get(m) == null) {
   9.158 +            hashOnId.put(m, o);
   9.159          }
   9.160 -        //makeHardRef(o);
   9.161 -        makeHardRef(cr);
   9.162 -        checkQueue();
   9.163 +        makeHardRef(m, o);
   9.164          int curSize = hashOnId.size();
   9.165 -        if (curSize > maxSize)
   9.166 +        if (curSize > maxSize) {
   9.167              maxSize = curSize;
   9.168 +        }
   9.169      }
   9.170  
   9.171      /** get an object from the cache
   9.172      * @param m the object's MOF ID
   9.173      */
   9.174      public synchronized Object get(Object m) {
   9.175 -        Object o = null;
   9.176 -        CacheReference cr = (CacheReference)hashOnId.get(m);
   9.177 -        if (cr != null)
   9.178 -            o = cr.get();
   9.179 +        Object o = hashOnId.get(m);
   9.180          if (o != null) {
   9.181 -            makeHardRef(cr);
   9.182 +            makeHardRef(m, o);
   9.183              hits++;
   9.184 -        }
   9.185 -        else {
   9.186 +        } else {
   9.187              misses++;
   9.188          }
   9.189 -        checkQueue();
   9.190          return o;
   9.191      }
   9.192  
   9.193 @@ -172,25 +233,16 @@
   9.194      * @return true if the object was found in the cache
   9.195      */
   9.196      public synchronized void remove(Object m) {
   9.197 -        CacheReference cr = (CacheReference)hashOnId.remove(m);
   9.198 -
   9.199          if (!removeFromCache(m)) {
   9.200              deleted.put(m, m);
   9.201          }
   9.202 -
   9.203 -        checkQueue();
   9.204      }
   9.205  
   9.206      /** remove all traces from the cache.  
   9.207      * @return true if the object was new
   9.208      */
   9.209      private boolean removeFromCache(Object m) {
   9.210 -        CacheReference cr = (CacheReference)hashOnId.remove(m);
   9.211 -
   9.212 -        if (cr != null)  {
   9.213 -            cr.clear();
   9.214 -            //cr.inCache = false;
   9.215 -        }
   9.216 +        hashOnId.remove(m);
   9.217          boolean wasNew = (newOnes.remove(m) != null);
   9.218          dirty.remove(m);
   9.219  
   9.220 @@ -201,77 +253,54 @@
   9.221      /** clear all unecessary objects from the cache
   9.222      */
   9.223      public synchronized void clear() {
   9.224 -        Arrays.fill(hardRef, null);
   9.225 +        hardRef.clear();
   9.226          System.gc();
   9.227 -        checkQueue();
   9.228      }
   9.229  
   9.230      /* create a hard reference to the supplied object */
   9.231 -    //private void makeHardRef(Object o) {
   9.232 -    private void makeHardRef(CacheReference cr) {
   9.233 -        /**
   9.234 -        hardRef[hardIndex++] = o;
   9.235 -        if (hardIndex >= hardRef.length) {
   9.236 -            hardIndex = 0;
   9.237 +    private void makeHardRef(Object m, Object o) {
   9.238 +        hardRef.put(m, o);
   9.239 +    }
   9.240 +    
   9.241 +    void updateSize() {
   9.242 +	int allChanged = newOnes.size() + dirty.size();
   9.243 +        int sizeDelta = allChanged - lastLocalSize;
   9.244 +        lastLocalSize = allChanged;
   9.245 +        synchronized (MDRCache.this) {
   9.246 +            size += sizeDelta;
   9.247          }
   9.248 -
   9.249 -        BHM: This was not very nice after 20 gets We'd have 20
   9.250 -             identical objects in the cache which definitely isn't
   9.251 -             what we want.
   9.252 -        */
   9.253 -
   9.254 -        if ( cr.isHard() ) {
   9.255 -            // The reference is already in cache we don't need to do
   9.256 -            // anything
   9.257 -            return;
   9.258 -        }
   9.259 -        else {
   9.260 -            if (hardRef[hardIndex] != null) {
   9.261 -                // Old Reference may be GCed 
   9.262 -                hardRef[hardIndex].weaken();
   9.263 -            }
   9.264 -            cr.harden();
   9.265 -            hardRef[hardIndex] = cr;
   9.266 -
   9.267 -            hardIndex++;
   9.268 -            if ( hardIndex >= hardRef.length ) {
   9.269 -                hardIndex = 0;
   9.270 -            }
   9.271 -        }
   9.272 -    }
   9.273 -
   9.274 -    /* check for queued references, and remove them from the hash table */
   9.275 -    private void checkQueue() {
   9.276 -	int i = 0;
   9.277 -        CacheReference cr;
   9.278 -        while ((cr = (CacheReference)queue.poll()) != null) {
   9.279 -            //if (cr.inCache) {
   9.280 -            Object k = cr.getKey();
   9.281 -            if (k == null)
   9.282 -                // the reference was already replaced by another one.
   9.283 -                continue;
   9.284 -
   9.285 -            CacheReference cr2 = (CacheReference)hashOnId.remove(k);
   9.286 -            i += cr2 == null ? 0 : 1;
   9.287 -            // cr.inCache = false;
   9.288 -            //}
   9.289 -        }
   9.290 -        /*
   9.291 -	if (i > 0) {
   9.292 -	    Logger.getDefault().log("Removed " + i +
   9.293 -		" references; hash size now " + hashOnId.size() + " was " + (hashOnId.size() + i));
   9.294 -            Logger.getDefault().log( " HardRefs " + hardIndex );
   9.295 -	}
   9.296 -        */
   9.297      }
   9.298  
   9.299      /* Check to see if we have exceeded our threshhold for dirty objects
   9.300      */
   9.301      private void checkThreshhold() throws StorageException {
   9.302 -	int allChanged = newOnes.size() + dirty.size();  
   9.303 -	// Logger.getDefault().log("checkThreshhold called at level " + allChanged);
   9.304 -    	if (allChanged >= threshhold)
   9.305 +	int allChanged = newOnes.size() + dirty.size();
   9.306 +        int sizeDelta = allChanged - lastLocalSize;
   9.307 +        lastLocalSize = allChanged;
   9.308 +        synchronized (MDRCache.this) {
   9.309 +            size += sizeDelta;
   9.310 +            if (size >= threshhold) {
   9.311 +                //System.err.println("Global threshhold reached at: " + size);
   9.312 +                int newSize = 0;
   9.313 +                for (Iterator it = instances.iterator(); it.hasNext();) {
   9.314 +                    MDRCache cache = (MDRCache) it.next();
   9.315 +                    allChanged = cache.newOnes.size() + cache.dirty.size();
   9.316 +                    if (allChanged > 10) {
   9.317 +                        //System.err.println("    ...Threshhold reached at level " + allChanged);
   9.318 +                        cache.handler.cacheThreshholdReached(cache, allChanged);
   9.319 +                        allChanged = cache.newOnes.size() + cache.dirty.size();
   9.320 +                    }
   9.321 +                    cache.lastLocalSize = allChanged;
   9.322 +                    newSize += allChanged;
   9.323 +                }
   9.324 +                size = newSize;
   9.325 +                return;
   9.326 +            }                
   9.327 +        }
   9.328 +    	if (allChanged >= localThreshhold) {
   9.329 +            //System.err.println("Threshhold reached at level " + allChanged + ", global cache size: " + size);
   9.330  	    handler.cacheThreshholdReached(this, allChanged);
   9.331 +        }
   9.332      }
   9.333  
   9.334      /* throw an exception when a bad key is processed */
   9.335 @@ -423,4 +452,58 @@
   9.336  	void cacheThreshholdReached(MDRCache cache, int size) 
   9.337  						throws StorageException;
   9.338      }
   9.339 +    
   9.340 +    private static class FacilityCache extends HashMap {
   9.341 +        private final ReferenceQueue queue = new ReferenceQueue();
   9.342 +        private boolean cleaningUp = false;
   9.343 +
   9.344 +        private class CacheReference extends WeakReference {
   9.345 +            private Object key;
   9.346 +
   9.347 +            public CacheReference(Object key, Object object) {
   9.348 +                super(object, queue);
   9.349 +                this.key = key;
   9.350 +            }
   9.351 +
   9.352 +            public Object getKey() {
   9.353 +                return key;
   9.354 +            }
   9.355 +        }
   9.356 +
   9.357 +        private void cleanUp() {
   9.358 +            assert !cleaningUp;
   9.359 +            CacheReference reference;
   9.360 +            cleaningUp = true;
   9.361 +            try {
   9.362 +                while ((reference = (CacheReference) queue.poll()) != null) {
   9.363 +                    Object key = reference.getKey();
   9.364 +                    java.lang.ref.Reference currentRef = (java.lang.ref.Reference) super.remove(key);
   9.365 +                    if (currentRef != null && currentRef != reference && currentRef.get() != null) {
   9.366 +                        super.put(key, currentRef);
   9.367 +                    }
   9.368 +                }
   9.369 +            } finally {
   9.370 +                cleaningUp = false;
   9.371 +            }
   9.372 +        }
   9.373 +
   9.374 +        public Object put(Object key, Object value) {
   9.375 +            cleanUp();
   9.376 +            Object result = super.put(key, new CacheReference(key, value));
   9.377 +            assert result == null || ((CacheReference) result).get() == null : "replacing non-null reference";
   9.378 +            return null;
   9.379 +        }
   9.380 +        
   9.381 +        public Object remove(Object key) {
   9.382 +            cleanUp();
   9.383 +            Object result = super.remove(key);
   9.384 +            return result == null ? null : ((CacheReference) result).get();
   9.385 +        }
   9.386 +
   9.387 +        public Object get(Object key) {
   9.388 +            cleanUp();
   9.389 +            Object result = super.get(key);
   9.390 +            return result == null ? null : ((CacheReference) result).get();
   9.391 +        }
   9.392 +    }
   9.393  }
    10.1 --- a/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/TransactionCache.java	Mon Aug 23 08:51:22 2004 +0000
    10.2 +++ b/mdr/src/org/netbeans/mdr/persistence/btreeimpl/btreestorage/TransactionCache.java	Mon Aug 30 16:57:50 2004 +0000
    10.3 @@ -18,7 +18,8 @@
    10.4  public class TransactionCache {
    10.5  
    10.6      // max. number of cached operations
    10.7 -    private static final int TRESHOLD = 500;
    10.8 +    private static final int GLOBAL_TRESHOLD = 768;
    10.9 +    private static final int LOCAL_TRESHOLD = 512;
   10.10      
   10.11      // operations codes
   10.12      public static final byte OP_INSERT = 0;
   10.13 @@ -26,7 +27,9 @@
   10.14      public static final byte OP_REPLACE = 2;
   10.15      
   10.16      // number of cached operations
   10.17 -    private int cacheSize = 0;
   10.18 +    private static int cacheSize = 0;
   10.19 +    private int localCacheSize = 0;
   10.20 +    private boolean tresholdReached = false;
   10.21      
   10.22      // true if transaction cache stores some commited operations
   10.23      private boolean dataCommited = false;
   10.24 @@ -43,7 +46,7 @@
   10.25       * @return true if transaction cache treshold has been reached
   10.26       */
   10.27      public boolean tresholdReached () {
   10.28 -        return cacheSize >= TRESHOLD;
   10.29 +        return tresholdReached;
   10.30      }
   10.31      
   10.32      /**
   10.33 @@ -58,32 +61,45 @@
   10.34       */
   10.35      public void clear () {
   10.36          operations = new LinkedList ();                
   10.37 -        commitedOperations.clear ();        
   10.38 -        cacheSize = 0;
   10.39 +        commitedOperations.clear ();
   10.40 +        synchronized (TransactionCache.class) {
   10.41 +            cacheSize -= localCacheSize;
   10.42 +            localCacheSize = 0;
   10.43 +            tresholdReached = false;
   10.44 +        }
   10.45          dataCommited = false;
   10.46      }
   10.47      
   10.48 +    private void incrementCacheSize() {
   10.49 +        synchronized (TransactionCache.class) {
   10.50 +            localCacheSize++;
   10.51 +            cacheSize++;
   10.52 +     
   10.53 +            tresholdReached |= cacheSize >= GLOBAL_TRESHOLD || localCacheSize >= LOCAL_TRESHOLD;
   10.54 +        }
   10.55 +    }
   10.56 +    
   10.57      /** adds one insert operation */
   10.58      public void addInserted (MOFID id, byte [] value) {
   10.59 -        if (cacheSize < TRESHOLD) {
   10.60 +        if (!tresholdReached) {
   10.61              operations.addLast (new Record (OP_INSERT, id, value));
   10.62 -            cacheSize++;
   10.63 +            incrementCacheSize();
   10.64          }
   10.65      }
   10.66      
   10.67      /** adds one delete operation */
   10.68      public void addDeleted (MOFID id) {
   10.69 -        if (cacheSize < TRESHOLD) {
   10.70 +        if (!tresholdReached) {
   10.71              operations.addLast ((new Record (OP_DELETE, id, null)));
   10.72 -            cacheSize++;
   10.73 +            incrementCacheSize();
   10.74          }
   10.75      }
   10.76      
   10.77      /** adds one replace operation */
   10.78      public void addReplaced (MOFID id, byte [] value) {
   10.79 -        if (cacheSize < TRESHOLD) {
   10.80 +        if (!tresholdReached) {
   10.81              operations.addLast (new Record (OP_REPLACE, id, value));
   10.82 -            cacheSize++;
   10.83 +            incrementCacheSize();
   10.84          }
   10.85      }
   10.86