Heap usage significantly improved. Caches are now static rather than per storage file.
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