diff options
Diffstat (limited to 'platform/util/src/com/intellij/util/io')
4 files changed, 126 insertions, 57 deletions
diff --git a/platform/util/src/com/intellij/util/io/IntToIntBtree.java b/platform/util/src/com/intellij/util/io/IntToIntBtree.java index b17fc6cc5c6c..475f3cb67a94 100644 --- a/platform/util/src/com/intellij/util/io/IntToIntBtree.java +++ b/platform/util/src/com/intellij/util/io/IntToIntBtree.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,7 +30,7 @@ import java.util.Arrays; * Date: 7/12/11 * Time: 1:34 PM */ -class IntToIntBtree { +public class IntToIntBtree { public static int version() { return 4 + (IOUtil.ourByteBuffersUseNativeByteOrder ? 0xFF : 0); } @@ -55,10 +55,10 @@ class IntToIntBtree { private boolean hasZeroKey; private int zeroKeyValue; - private boolean isLarge = true; + private final boolean isLarge = true; private final ResizeableMappedFile storage; private final boolean offloadToSiblingsBeforeSplit = false; - private boolean indexNodeIsHashTable = true; + private final boolean indexNodeIsHashTable = true; final int metaDataLeafPageLength; final int hashPageCapacity; @@ -66,8 +66,8 @@ class IntToIntBtree { private TIntIntHashMap myCachedMappings; private final int myCachedMappingsSize; - public IntToIntBtree(int _pageSize, File file, PagedFileStorage.StorageLockContext storageLockContext, boolean initial) throws IOException { - pageSize = _pageSize; + public IntToIntBtree(int pageSize, @NotNull File file, @NotNull PagedFileStorage.StorageLockContext storageLockContext, boolean initial) throws IOException { + this.pageSize = pageSize; if (initial) { FileUtil.delete(file); @@ -82,13 +82,12 @@ class IntToIntBtree { root.setIndexLeaf(true); } - int i = (pageSize - BtreePage.RESERVED_META_PAGE_LEN) / BtreeIndexNodeView.INTERIOR_SIZE - 1; + int i = (this.pageSize - BtreePage.RESERVED_META_PAGE_LEN) / BtreeIndexNodeView.INTERIOR_SIZE - 1; assert i < Short.MAX_VALUE && i % 2 == 0; maxInteriorNodes = (short)i; maxLeafNodes = (short)i; - int metaPageLen = BtreePage.RESERVED_META_PAGE_LEN; - + int metaPageLen; if (indexNodeIsHashTable) { ++i; while(!isPrime(i)) i -= 2; @@ -97,8 +96,10 @@ class IntToIntBtree { metaPageLen = BtreePage.RESERVED_META_PAGE_LEN; i = (int)(hashPageCapacity * 0.9); if ((i & 1) == 1) ++i; - } else { + } + else { hashPageCapacity = -1; + metaPageLen = BtreePage.RESERVED_META_PAGE_LEN; } metaDataLeafPageLength = metaPageLen; @@ -108,20 +109,18 @@ class IntToIntBtree { if (hasCachedMappings) { myCachedMappings = new TIntIntHashMap(myCachedMappingsSize = 4 * maxLeafNodes); - } else { + } + else { myCachedMappings = null; myCachedMappingsSize = -1; } } - public void persistVars(BtreeDataStorage storage, boolean toDisk) { - if (toDisk) { - storage.persistInt(0, height | (hasZeroKey ? HAS_ZERO_KEY_MASK :0), true); - } else { - int i = storage.persistInt(0, 0, false); - hasZeroKey = (i & HAS_ZERO_KEY_MASK) != 0; - height = i & ~HAS_ZERO_KEY_MASK; - } + // return total number of bytes needed for storing information + public int persistVars(@NotNull BtreeDataStorage storage, boolean toDisk) { + int i = storage.persistInt(0, height | (hasZeroKey ? HAS_ZERO_KEY_MASK :0), toDisk); + hasZeroKey = (i & HAS_ZERO_KEY_MASK) != 0; + height = i & ~HAS_ZERO_KEY_MASK; pagesCount = storage.persistInt(4, pagesCount, toDisk); movedMembersCount = storage.persistInt(8, movedMembersCount, toDisk); @@ -132,9 +131,10 @@ class IntToIntBtree { hashedPagesCount = storage.persistInt(28, hashedPagesCount, toDisk); root.setAddress(storage.persistInt(32, root.address, toDisk)); zeroKeyValue = storage.persistInt(36, zeroKeyValue, toDisk); + return 40; } - interface BtreeDataStorage { + public interface BtreeDataStorage { int persistInt(int offset, int value, boolean toDisk); } @@ -155,10 +155,11 @@ class IntToIntBtree { } private BtreeIndexNodeView myAccessNodeView; - private int myLastGetKey, myOptimizedInserts; + private int myLastGetKey; + private int myOptimizedInserts; private boolean myCanUseLastKey; - public boolean get(int key, int[] result) { + public boolean get(int key, @NotNull int[] result) { if (key == 0) { if (hasZeroKey) { result[0] = zeroKeyValue; @@ -199,7 +200,8 @@ class IntToIntBtree { if (hasCachedMappings) { myCachedMappings.put(key, value); if (myCachedMappings.size() == myCachedMappingsSize) flushCachedMappings(); - } else { + } + else { boolean canUseLastKey = myCanUseLastKey; if (canUseLastKey) { myCanUseLastKey = false; @@ -256,12 +258,12 @@ class IntToIntBtree { } } - void doClose() throws IOException { + public void doClose() throws IOException { myCachedMappings = null; storage.close(); } - void doFlush() { + public void doFlush() { flushCachedMappings(); storage.force(); } @@ -445,11 +447,11 @@ class IntToIntBtree { putInt(offset, value); } - private final int indexToOffset(int i) { + private int indexToOffset(int i) { return i * INTERIOR_SIZE + (isHashedLeaf() ? btree.metaDataLeafPageLength:RESERVED_META_PAGE_LEN); } - private final int keyAt(int i) { + private int keyAt(int i) { if (doSanityCheck) { if (isHashedLeaf()) myAssert(i < btree.hashPageCapacity); else myAssert(i < getChildrenCount()); @@ -495,7 +497,7 @@ class IntToIntBtree { setFlag(INDEX_LEAF_MASK, value); } - private final boolean isHashedLeaf() { + private boolean isHashedLeaf() { return isHashedLeaf; } @@ -608,7 +610,8 @@ class IntToIntBtree { if (hashedLeaf) { hashLeafData = new HashLeafData(this, recordCount); if (doOffloadToSiblingsWhenHashed(parent, hashLeafData)) return parentAddress; - } else { + } + else { if (doOffloadToSiblingsSorted(parent)) return parentAddress; } } @@ -1074,16 +1077,14 @@ class IntToIntBtree { private static final boolean useDoubleHash = true; private int hashIndex(int value) { - int hash, index; - final int length = btree.hashPageCapacity; - hash = value & 0x7fffffff; - index = hash % length; + int hash = value & 0x7fffffff; + int index = hash % length; int keyAtIndex = keyAt(index); - int total = 0; btree.hashSearchRequests++; + int total = 0; if (useDoubleHash) { if (keyAtIndex != value && keyAtIndex != HASH_FREE) { // see Knuth, p. 529 @@ -1148,11 +1149,21 @@ class IntToIntBtree { if (childrenAddresses.length > 0) { BtreeIndexNodeView child = new BtreeIndexNodeView(this); - for(int i = 0; i < childrenAddresses.length; ++i) { - child.setAddress(childrenAddresses[i]); - if (!processLeafPages(child, processor)) return false; + for (int childrenAddress : childrenAddresses) { + child.setAddress(childrenAddress); + if (!processLeafPages(child, processor)) return false; } } return true; } + + public void withStorageLock(@NotNull Runnable runnable) { + storage.getPagedFileStorage().lock(); + try { + runnable.run(); + } + finally { + storage.getPagedFileStorage().unlock(); + } + } } diff --git a/platform/util/src/com/intellij/util/io/PagedFileStorage.java b/platform/util/src/com/intellij/util/io/PagedFileStorage.java index 69315f1b3764..1fca8e063394 100644 --- a/platform/util/src/com/intellij/util/io/PagedFileStorage.java +++ b/platform/util/src/com/intellij/util/io/PagedFileStorage.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -88,11 +88,11 @@ public class PagedFileStorage implements Forceable { private static final ByteOrder ourNativeByteOrder = ByteOrder.nativeOrder(); public void lock() { - myStorageLockContext.myLock.lock(); + myStorageLockContext.lock(); } public void unlock() { - myStorageLockContext.myLock.unlock(); + myStorageLockContext.unlock(); } public StorageLockContext getStorageLockContext() { @@ -510,11 +510,11 @@ public class PagedFileStorage implements Forceable { } public void lock() { - myDefaultStorageLockContext.myLock.lock(); + myDefaultStorageLockContext.lock(); } public void unlock() { - myDefaultStorageLockContext.myLock.unlock(); + myDefaultStorageLockContext.unlock(); } private int registerPagedFileStorage(@NotNull PagedFileStorage storage) { @@ -658,7 +658,9 @@ public class PagedFileStorage implements Forceable { LOG.info("Max memory:"+maxMemory.get(null) + ", reserved memory:" + reservedMemory.get(null)); } } - catch (Throwable t) {} + catch (Throwable t) { + + } throw new MappingFailedException( "Cannot recover from OOME in memory mapping: -Xmx=" + Runtime.getRuntime().maxMemory() / MB + "MB " + "new size limit: " + mySizeLimit / MB + "MB " + @@ -669,7 +671,7 @@ public class PagedFileStorage implements Forceable { } } - private void checkThreadAccess(StorageLockContext storageLockContext) { + private static void checkThreadAccess(StorageLockContext storageLockContext) { if (storageLockContext.myCheckThreadAccess && !storageLockContext.myLock.isHeldByCurrentThread()) { throw new IllegalStateException("Must hold StorageLock lock to access PagedFileStorage"); } @@ -776,5 +778,12 @@ public class PagedFileStorage implements Forceable { public StorageLockContext(boolean checkAccess) { this(ourLock, checkAccess); } + + public void lock() { + myLock.lock(); + } + public void unlock() { + myLock.unlock(); + } } } diff --git a/platform/util/src/com/intellij/util/io/RandomAccessDataFile.java b/platform/util/src/com/intellij/util/io/RandomAccessDataFile.java index 9a297bcef6d1..d4383a55d03e 100644 --- a/platform/util/src/com/intellij/util/io/RandomAccessDataFile.java +++ b/platform/util/src/com/intellij/util/io/RandomAccessDataFile.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,11 +47,11 @@ public class RandomAccessDataFile implements Forceable, Closeable { private static final boolean DEBUG = false; - public RandomAccessDataFile(final File file) throws IOException { + public RandomAccessDataFile(@NotNull File file) throws IOException { this(file, PagePool.SHARED); } - public RandomAccessDataFile(final File file, final PagePool pool) throws IOException { + public RandomAccessDataFile(@NotNull File file, @NotNull PagePool pool) throws IOException { myPool = pool; myFile = file; if (!file.exists()) { @@ -201,6 +201,9 @@ public class RandomAccessDataFile implements Forceable, Closeable { dispose(); } + /** + * Flushes dirty pages to underlying buffers + */ @Override public void force() { assertNotDisposed(); @@ -210,6 +213,23 @@ public class RandomAccessDataFile implements Forceable, Closeable { } } + /** + * Flushes dirty pages to buffers and saves them to disk + */ + public void sync() { + force(); + try { + RandomAccessFile file = getRandomAccessFile(); + file.getChannel().force(true); + } + catch (IOException ignored) { + + } + finally { + releaseFile(); + } + } + public void flushSomePages(int maxPagesToFlush) { assertNotDisposed(); if (isDirty()) { @@ -229,7 +249,7 @@ public class RandomAccessDataFile implements Forceable, Closeable { private void assertNotDisposed() { if (myIsDisposed) { - LOG.assertTrue(false, "storage file is disposed: " + myFile); + LOG.error("storage file is disposed: " + myFile); } } @@ -316,6 +336,7 @@ public class RandomAccessDataFile implements Forceable, Closeable { file.seek(fileOffset); } + @Override public int hashCode() { return myCount; } diff --git a/platform/util/src/com/intellij/util/io/storage/HeavyProcessLatch.java b/platform/util/src/com/intellij/util/io/storage/HeavyProcessLatch.java index e0d349c0c7ad..663cd215cfbe 100644 --- a/platform/util/src/com/intellij/util/io/storage/HeavyProcessLatch.java +++ b/platform/util/src/com/intellij/util/io/storage/HeavyProcessLatch.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,19 +19,47 @@ */ package com.intellij.util.io.storage; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.util.Disposer; +import com.intellij.util.EventDispatcher; +import org.jetbrains.annotations.NotNull; + +import java.util.EventListener; +import java.util.concurrent.atomic.AtomicInteger; + public class HeavyProcessLatch { public static final HeavyProcessLatch INSTANCE = new HeavyProcessLatch(); - private int myHeavyProcessCounter = 0; - - public synchronized void processStarted() { - myHeavyProcessCounter++; + + private final AtomicInteger myHeavyProcessCounter = new AtomicInteger(); + private final EventDispatcher<HeavyProcessListener> myEventDispatcher = EventDispatcher.create(HeavyProcessListener.class); + + private HeavyProcessLatch() { + } + + public void processStarted() { + myHeavyProcessCounter.incrementAndGet(); + myEventDispatcher.getMulticaster().processStarted(); } - public synchronized void processFinished() { - myHeavyProcessCounter--; + public void processFinished() { + myHeavyProcessCounter.decrementAndGet(); + myEventDispatcher.getMulticaster().processFinished(); + } + + public boolean isRunning() { + return myHeavyProcessCounter.get() != 0; + } + + public interface HeavyProcessListener extends EventListener { + public void processStarted(); + + public void processFinished(); } - public synchronized boolean isRunning() { - return myHeavyProcessCounter != 0; + @NotNull + public Disposable addListener(@NotNull HeavyProcessListener listener) { + Disposable disposable = Disposer.newDisposable(); + myEventDispatcher.addListener(listener, disposable); + return disposable; } }
\ No newline at end of file |