From: <mar...@us...> - 2010-09-01 17:46:18
|
Revision: 3487 http://bigdata.svn.sourceforge.net/bigdata/?rev=3487&view=rev Author: martyncutcher Date: 2010-09-01 17:46:11 +0000 (Wed, 01 Sep 2010) Log Message: ----------- Refactor of IAllocationContext Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractTask.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalDelegate.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/IRawStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/Allocator.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/BlobAllocator.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractMRMWTestCase.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentTx.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Added Paths: ----------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/JournalShadow.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/ReplicatedStore.java/ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/ReplicatedStoreService.java/ Removed Paths: ------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IAllocationContext.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalShadow.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -319,12 +319,12 @@ * * Toggle comment appropriately to activate/deactivate */ -// final long[] addrsUsed = new long[4024 * 1024]; -// int addrsUsedCurs = 0; -// final char[] addrActions = new char[addrsUsed.length]; -// final int[] addrLens = new int[addrsUsed.length]; - final long[] addrsUsed = null; +/* final long[] addrsUsed = new long[4024 * 1024]; int addrsUsedCurs = 0; + final char[] addrActions = new char[addrsUsed.length]; + final int[] addrLens = new int[addrsUsed.length]; +*/ final long[] addrsUsed = null; + int addrsUsedCurs = 0; final char[] addrActions = null; final int[] addrLens = null; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -88,6 +88,7 @@ import com.bigdata.rawstore.WormAddressManager; import com.bigdata.relation.locator.IResourceLocator; import com.bigdata.resources.ResourceManager; +import com.bigdata.rwstore.IAllocationContext; import com.bigdata.service.DataService; import com.bigdata.service.EmbeddedClient; import com.bigdata.service.IBigdataClient; @@ -986,8 +987,6 @@ this._rootBlock = fileMetadata.rootBlock; - setCommitter(DELETEBLOCK, new DeleteBlockCommitter((RWStrategy) _bufferStrategy)); - break; } @@ -2611,11 +2610,11 @@ } public long write(ByteBuffer data, final long oldAddr, IAllocationContext context) { - return _bufferStrategy.write(data, oldAddr, context); + return ((RWStrategy)_bufferStrategy).write(data, oldAddr, context); } public long write(ByteBuffer data, IAllocationContext context) { - return _bufferStrategy.write(data, context); + return ((RWStrategy)_bufferStrategy).write(data, context); } // Note: NOP for WORM. Used by RW for eventual recycle protocol. @@ -2631,12 +2630,12 @@ assertCanWrite(); - _bufferStrategy.delete(addr, context); + ((RWStrategy)_bufferStrategy).delete(addr, context); } public void detachContext(IAllocationContext context) { - _bufferStrategy.detachContext(context); + ((RWStrategy)_bufferStrategy).detachContext(context); } final public long getRootAddr(final int index) { @@ -2771,7 +2770,17 @@ * Register committer to write previous root block */ setCommitter(PREV_ROOTBLOCK, new RootBlockCommitter(this)); + + /** + * If the strategy is a RWStrategy, then register the delete + * block committer to store the deferred deletes for each + * commit record. + */ + if (_bufferStrategy instanceof RWStrategy) + setCommitter(DELETEBLOCK, new DeleteBlockCommitter((RWStrategy) _bufferStrategy)); + + } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractTask.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractTask.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractTask.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -71,6 +71,7 @@ import com.bigdata.resources.ResourceManager; import com.bigdata.resources.StaleLocatorException; import com.bigdata.resources.StaleLocatorReason; +import com.bigdata.rwstore.IAllocationContext; import com.bigdata.sparse.GlobalRowStoreHelper; import com.bigdata.sparse.SparseRowStore; import com.bigdata.util.InnerCause; @@ -2893,22 +2894,6 @@ return delegate.getRootBlocks(startTime); } - public void delete(long addr, IAllocationContext context) { - throw new UnsupportedOperationException(); - } - - public long write(ByteBuffer data, IAllocationContext context) { - throw new UnsupportedOperationException(); - } - - public long write(ByteBuffer data, long oldAddr, IAllocationContext context) { - throw new UnsupportedOperationException(); - } - - public void detachContext(IAllocationContext context) { - delegate.detachContext(context); - } - } /** Deleted: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IAllocationContext.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IAllocationContext.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IAllocationContext.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -1,41 +0,0 @@ -/** - -Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. - -Contact: - SYSTAP, LLC - 4501 Tower Road - Greensboro, NC 27410 - lic...@bi... - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package com.bigdata.journal; - -/** - * An IAllocationContext defines a shadow environment which may be - * associated with allocations made during a transaction. - * - * @author Martyn Cutcher - * - */ -public interface IAllocationContext extends Comparable { - - /** - * @return the minimum release time for any freed allocations - */ - long minimumReleaseTime(); - -} Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalDelegate.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalDelegate.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalDelegate.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -38,12 +38,13 @@ import com.bigdata.counters.CounterSet; import com.bigdata.mdi.IResourceMetadata; import com.bigdata.relation.locator.IResourceLocator; +import com.bigdata.rwstore.IAllocationContext; import com.bigdata.sparse.SparseRowStore; public class JournalDelegate implements IJournal { - final IJournal delegate; + protected final AbstractJournal delegate; - public JournalDelegate(final IJournal source) { + public JournalDelegate(final AbstractJournal source) { this.delegate = source; } @@ -226,20 +227,4 @@ public TemporaryStore getTempStore() { return delegate.getTempStore(); } - - public void delete(long addr, IAllocationContext context) { - delegate.delete(addr, context); - } - - public long write(ByteBuffer data, IAllocationContext context) { - return delegate.write(data, context); - } - - public long write(ByteBuffer data, long oldAddr, IAllocationContext context) { - return delegate.write(data, oldAddr, context); - } - - public void detachContext(IAllocationContext context) { - delegate.detachContext(context); - } } Deleted: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalShadow.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalShadow.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalShadow.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -1,85 +0,0 @@ -/** - -Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. - -Contact: - SYSTAP, LLC - 4501 Tower Road - Greensboro, NC 27410 - lic...@bi... - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -package com.bigdata.journal; - -import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicLong; - -/** - * A JournalShadow wraps a Journal as a JournalDelegate but provides itself - * as the allocation context to be passed through to any interested - * BufferStrategy. - * - * This is the path by which RWStore allocators are provided the context for - * the allocations and deletes made - * - * @author Martyn Cutcher - * - */ -public class JournalShadow extends JournalDelegate implements IAllocationContext { - static AtomicLong s_idCounter = new AtomicLong(23); - int m_id = (int) s_idCounter.incrementAndGet(); - - public JournalShadow(IJournal source) { - super(source); - } - - public long write(ByteBuffer data) { - return delegate.write(data, this); - } - - public long write(ByteBuffer data, long oldAddr) { - return delegate.write(data, oldAddr, this); - } - - public void delete(long oldAddr) { - delegate.delete(oldAddr, this); - } - - public int compareTo(Object o) { - if (o instanceof JournalShadow) { - JournalShadow js = (JournalShadow) o; - return m_id - js.m_id; - } else { - return -1; - } - } - - /** - * TODO: should retrieve from localTransactionService or Journal - * properties - */ - public long minimumReleaseTime() { - return 0; - } - - /** - * Release itself from the wrapped Journal, this unlocks the allocator for - * the RWStore - */ - public void detach() { - delegate.detachContext(this); - } -} Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -42,6 +42,7 @@ import com.bigdata.quorum.Quorum; import com.bigdata.rawstore.AbstractRawStore; import com.bigdata.rawstore.IAddressManager; +import com.bigdata.rwstore.IAllocationContext; import com.bigdata.rwstore.RWStore; import com.bigdata.service.AbstractTransactionService; import com.bigdata.util.ChecksumUtility; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -30,7 +30,7 @@ import java.nio.ByteBuffer; import com.bigdata.LRUNexus; -import com.bigdata.journal.IAllocationContext; +import com.bigdata.rwstore.IAllocationContext; /** * Abstract base class for {@link IRawStore} implementations. This class uses a Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/IRawStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/IRawStore.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rawstore/IRawStore.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -37,8 +37,8 @@ import com.bigdata.counters.CounterSet; import com.bigdata.io.IByteArrayBuffer; import com.bigdata.journal.AbstractJournal; -import com.bigdata.journal.IAllocationContext; import com.bigdata.mdi.IResourceMetadata; +import com.bigdata.rwstore.IAllocationContext; /** * <p> @@ -124,8 +124,7 @@ */ public long write(ByteBuffer data); - /** - * Write the data (unisolated). + /** * * @param data * The data. The bytes from the current @@ -135,43 +134,6 @@ * {@link ByteBuffer#limit()} . The caller may subsequently * modify the contents of the buffer without changing the state * of the store (i.e., the data are copied into the store). - * - * @param context defines teh shadow AllocationContext from which this call - * was made - * - * @return A long integer formed that encodes both the offset from which the - * data may be read and the #of bytes to be read. See - * {@link IAddressManager}. - * - * @throws IllegalArgumentException - * if <i>data</i> is <code>null</code>. - * @throws IllegalArgumentException - * if <i>data</i> has zero bytes {@link ByteBuffer#remaining()}. - * @throws IllegalStateException - * if the store is not open. - * @throws IllegalStateException - * if the store does not allow writes. - * - * @todo define exception if the maximum extent would be exceeded. - * - * @todo the addresses need to reflect the ascending offset at which the - * data are written, at least for a class of append only store. some - * stores, such as the Journal, also have an offset from the start of - * the file to the start of the data region (in the case of the - * Journal it is used to hold the root blocks). - */ - public long write(ByteBuffer data, IAllocationContext context); - - /** - * - * @param data - * The data. The bytes from the current - * {@link ByteBuffer#position()} to the - * {@link ByteBuffer#limit()} will be written and the - * {@link ByteBuffer#position()} will be advanced to the - * {@link ByteBuffer#limit()} . The caller may subsequently - * modify the contents of the buffer without changing the state - * of the store (i.e., the data are copied into the store). * @param oldAddr as returned from a previous write of the same object, or zero if a new write * * @return A long integer formed that encodes both the offset from which the @@ -180,25 +142,6 @@ */ public long write(ByteBuffer data, long oldAddr); - /** - * - * @param data - * The data. The bytes from the current - * {@link ByteBuffer#position()} to the - * {@link ByteBuffer#limit()} will be written and the - * {@link ByteBuffer#position()} will be advanced to the - * {@link ByteBuffer#limit()} . The caller may subsequently - * modify the contents of the buffer without changing the state - * of the store (i.e., the data are copied into the store). - * @param oldAddr as returned from a previous write of the same object, or zero if a new write - * @param context defines the shadow AllocationContext from which this call is made - * - * @return A long integer formed that encodes both the offset from which the - * data may be read and the #of bytes to be read. See - * {@link IAddressManager}. - */ - public long write(ByteBuffer data, long oldAddr, IAllocationContext context); - /** * Delete the data (unisolated). * <p> @@ -226,48 +169,6 @@ public void delete(long addr); /** - * Delete the data (unisolated). - * <p> - * After this operation subsequent reads on the address MAY fail and the - * caller MUST NOT depend on the ability to read at that address. - * - * @param addr - * A long integer formed using {@link Addr} that encodes both the - * offset at which the data was written and the #of bytes that - * were written. - * - * @param context - * Defines the shadow AllocationContext from which this call is - * made. For RWStore this can be used to immediately free the - * allocation if it can be determined to have orignally have - * been requested from the same context. - * - * @exception IllegalArgumentException - * If the address is known to be invalid (never written or - * deleted). Note that the address 0L is always invalid. - * - * It is only applicable in the - * context of a garbage collection strategy. With an append only - * store and with eviction of btrees into index segments there - * is no reason to delete anything on the store - and nothing to - * keep track of the delete. - * - * However, with a Read-Write store it is a requirement, and a void - * implementation is provided for other stores. - */ - public void delete(long addr, IAllocationContext context); - - /** - * - * @param context - * Defines the shadow AllocationContext that may have been used - * to allocate or delete storage. The RWStore assigns - * Allocation areas to specific contexts and these must be - * released for use by others. - */ - public void detachContext(IAllocationContext context); - - /** * Read the data (unisolated). * * @param addr Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -27,7 +27,6 @@ import java.util.ArrayList; import com.bigdata.io.writecache.WriteCacheService; -import com.bigdata.journal.IAllocationContext; /** * Bit maps for an allocator. The allocator is a bit map managed as int[]s. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/Allocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/Allocator.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/Allocator.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -28,7 +28,6 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicLong; -import com.bigdata.journal.IAllocationContext; public interface Allocator extends Comparable { public int getBlockSize(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/BlobAllocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/BlobAllocator.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/BlobAllocator.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -7,7 +7,6 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicLong; -import com.bigdata.journal.IAllocationContext; import com.bigdata.util.ChecksumUtility; /** Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -30,7 +30,6 @@ import org.apache.log4j.Logger; -import com.bigdata.journal.IAllocationContext; import com.bigdata.util.ChecksumUtility; /** Copied: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java (from rev 3484, branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IAllocationContext.java) =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java (rev 0) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -0,0 +1,36 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package com.bigdata.rwstore; + +/** + * An IAllocationContext defines a shadow environment which may be + * associated with allocations made during a transaction. + * + * @author Martyn Cutcher + * + */ +public interface IAllocationContext { + +} Property changes on: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -26,7 +26,6 @@ import java.io.File; -import com.bigdata.journal.IAllocationContext; /************************************************************************************************ * The IStore interface provides persistent file-backed storage. Copied: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/JournalShadow.java (from rev 3484, branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/JournalShadow.java) =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/JournalShadow.java (rev 0) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/JournalShadow.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -0,0 +1,107 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package com.bigdata.rwstore; + +import java.nio.ByteBuffer; +import java.util.concurrent.atomic.AtomicLong; + +import com.bigdata.journal.AbstractJournal; +import com.bigdata.journal.IJournal; +import com.bigdata.journal.JournalDelegate; +import com.bigdata.journal.RWStrategy; + +/** + * A JournalShadow wraps a Journal as a JournalDelegate but provides itself + * as the allocation context to be passed through to any interested + * BufferStrategy. + * + * This is the path by which RWStore allocators are provided the context for + * the allocations and deletes made + * + * @author Martyn Cutcher + * + */ +public class JournalShadow extends JournalDelegate implements IAllocationContext { + static AtomicLong s_idCounter = new AtomicLong(23); + int m_id = (int) s_idCounter.incrementAndGet(); + + private JournalShadow(AbstractJournal source) { + super(source); + } + + public long write(ByteBuffer data) { + return delegate.write(data, this); + } + + public long write(ByteBuffer data, long oldAddr) { + return delegate.write(data, oldAddr, this); + } + + public void delete(long oldAddr) { + delegate.delete(oldAddr, this); + } + + public int compareTo(Object o) { + if (o instanceof JournalShadow) { + JournalShadow js = (JournalShadow) o; + return m_id - js.m_id; + } else { + return -1; + } + } + + /** + * TODO: should retrieve from localTransactionService or Journal + * properties + */ + public long minimumReleaseTime() { + return 0; + } + + /** + * Release itself from the wrapped Journal, this unlocks the allocator for + * the RWStore + */ + public void detach() { + delegate.detachContext(this); + } + + /** + * This factory pattern creates a shadow for a RWStrategy-backed Journal + * to support protected allocations while allowing for deletion and + * re-allocation where possible. If the Journal is not backed by a + * RWStrategy, then the original Journal is returned. + * + * @param journal - the journal to be shadowed + * @return the shadowed journal if necessary + */ + public static IJournal newShadow(AbstractJournal journal) { + if (journal.getBufferStrategy() instanceof RWStrategy) { + return new JournalShadow(journal); + } else { + return journal; + } + } +} Property changes on: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/JournalShadow.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -33,7 +33,6 @@ import org.apache.log4j.Logger; -import com.bigdata.journal.IAllocationContext; /************************************************************************ * PSOutputStream Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -35,6 +35,7 @@ import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; @@ -53,7 +54,6 @@ import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.CommitRecordIndex; import com.bigdata.journal.ForceEnum; -import com.bigdata.journal.IAllocationContext; import com.bigdata.journal.ICommitRecord; import com.bigdata.journal.IRootBlockView; import com.bigdata.journal.JournalTransactionService; @@ -2728,9 +2728,8 @@ m_allocationLock.lock(); try { int addrs = strBuf.readInt(); - System.out.println("Freeing deferred deletes: " + addrs); - while (addrs-- > 0) { + while (addrs-- > 0) { // while (false && addrs-- > 0) { int nxtAddr = strBuf.readInt(); Allocator alloc = getBlock(nxtAddr); @@ -2873,8 +2872,8 @@ } } - private TreeMap<IAllocationContext, ContextAllocation> m_contexts = - new TreeMap<IAllocationContext, ContextAllocation>(); + private HashMap<IAllocationContext, ContextAllocation> m_contexts = + new HashMap<IAllocationContext, ContextAllocation>(); ContextAllocation establishContextAllocation(IAllocationContext context) { ContextAllocation ret = m_contexts.get(context); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractMRMWTestCase.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractMRMWTestCase.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractMRMWTestCase.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -235,7 +235,7 @@ final long timeout = 20; - final int ntrials = 10000; + final int ntrials = 2000; final int nclients = 20; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentTx.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentTx.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentTx.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -130,6 +130,8 @@ */ public void test_concurrentClients() throws InterruptedException { + new Float("123.23"); + final Properties properties = getProperties(); final Journal journal = new Journal(properties); @@ -150,14 +152,13 @@ doConcurrentClientTest(// journal, // - 10,// timeout + 30,// timeout 20,// nclients - 1000, // ntrials + 500, // ntrials 3,// keylen 100,// nops .10// abortRate ); - } finally { journal.destroy(); @@ -337,7 +338,15 @@ } } - + + // Now test rootBlocks + int rootBlockCount = 0; + Iterator<IRootBlockView> rbvs = journal.getRootBlocks(10); // cannot use 0 + while (rbvs.hasNext()) { + IRootBlockView rbv = rbvs.next(); + rootBlockCount++; + } + // immediately terminate any tasks that are still running. log.warn("Shutting down now!"); journal.shutdownNow(); @@ -357,6 +366,7 @@ ret.put("naborted",""+naborted); ret.put("ncommitted",""+ncommitted); ret.put("nuncommitted", ""+nuncommitted); + ret.put("rootBlocks found", ""+rootBlockCount); ret.put("elapsed(ms)", ""+elapsed); ret.put("tps", ""+(ncommitted * 1000 / elapsed)); ret.put("bytesWritten", ""+bytesWritten); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -48,6 +48,7 @@ import com.bigdata.btree.IIndex; import com.bigdata.btree.IndexMetadata; import com.bigdata.rawstore.Bytes; +import com.bigdata.rwstore.JournalShadow; import com.bigdata.test.ExperimentDriver; import com.bigdata.test.ExperimentDriver.IComparisonTest; import com.bigdata.test.ExperimentDriver.Result; @@ -118,13 +119,13 @@ // } doConcurrentClientTest(journal,// - 10,// timeout + 80,// timeout 20,// nresources 1, // minLocks 3, // maxLocks 1000, // ntrials 3, // keyLen - 100, // nops + 1000, // nops 0.02d // failureRate ); @@ -404,76 +405,73 @@ */ public Object doTask() throws Exception { - // the index names on which the writer holds a lock. - final String[] resource = getResource(); - - final IIndex[] indices = new IIndex[resource.length]; - - for (int i = 0; i < resource.length; i++) { + // the index names on which the writer holds a lock. + final String[] resource = getResource(); - indices[i] = getJournal().getIndex(resource[i]); + final IIndex[] indices = new IIndex[resource.length]; - final Thread t = Thread.currentThread(); - - if (btrees.putIfAbsent(indices[i], t) != null) { + for (int i = 0; i < resource.length; i++) { + indices[i] = getJournal().getIndex(resource[i]); - throw new AssertionError( - "Unisolated index already in use: " + resource[i]); + final Thread t = Thread.currentThread(); - } + if (btrees.putIfAbsent(indices[i], t) != null) { - } - - try { + throw new AssertionError("Unisolated index already in use: " + resource[i]); - // Random write operations on the named index(s). + } - for (int i = 0; i < nops; i++) { + } - final IIndex ndx = indices[i % resource.length]; - - final byte[] key = new byte[keyLen]; + try { - r.nextBytes(key); + // Random write operations on the named index(s). - if (r.nextInt(100) > 10) { + for (int i = 0; i < nops; i++) { - byte[] val = new byte[5]; + final IIndex ndx = indices[i % resource.length]; - r.nextBytes(val); + final byte[] key = new byte[keyLen]; - ndx.insert(key, val); + r.nextBytes(key); - } else { + if (r.nextInt(100) > 10) { - ndx.remove(key); + byte[] val = new byte[5]; - } + r.nextBytes(val); - } + ndx.insert(key, val); - if (r.nextDouble() < failureRate) { + } else { - throw new SpuriousException(); + ndx.remove(key); - } + } - return null; - - } finally { + } - for(int i=0; i<resource.length; i++) { + if (r.nextDouble() < failureRate) { - final IIndex ndx = indices[i]; - - if (ndx != null) - btrees.remove(ndx); - - } + throw new SpuriousException(); - } - - } + } + + return null; + + } finally { + + for (int i = 0; i < resource.length; i++) { + + final IIndex ndx = indices[i]; + + if (ndx != null) + btrees.remove(ndx); + + } + + } + } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-09-01 17:41:31 UTC (rev 3486) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-09-01 17:46:11 UTC (rev 3487) @@ -44,9 +44,7 @@ import com.bigdata.journal.AbstractRestartSafeTestCase; import com.bigdata.journal.BufferMode; import com.bigdata.journal.DiskOnlyStrategy; -import com.bigdata.journal.IAllocationContext; import com.bigdata.journal.Journal; -import com.bigdata.journal.JournalShadow; import com.bigdata.journal.RWStrategy; import com.bigdata.journal.TestJournalBasics; import com.bigdata.journal.Journal.Options; @@ -939,22 +937,6 @@ } static class DummyAllocationContext implements IAllocationContext { - static int s_id = 23; - - int m_id = s_id++; - - public int compareTo(Object o) { - if (o instanceof DummyAllocationContext) { - return m_id - ((DummyAllocationContext) o).m_id; - } else { - return -1; - } - } - - public long minimumReleaseTime() { - return 0; // indicates immediate release - } - } /** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-09-17 10:19:33
|
Revision: 3576 http://bigdata.svn.sourceforge.net/bigdata/?rev=3576&view=rev Author: martyncutcher Date: 2010-09-17 10:19:27 +0000 (Fri, 17 Sep 2010) Log Message: ----------- Implement BufferedWrites and Allocation locality enhancements Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWWriteCacheService.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWriteCache.java Added Paths: ----------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java Added: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java (rev 0) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -0,0 +1,108 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package com.bigdata.io.writecache; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +import com.bigdata.io.DirectBufferPool; +import com.bigdata.io.FileChannelUtility; +import com.bigdata.io.IReopenChannel; +import com.bigdata.rwstore.RWStore; + +/** + * The BufferedWrite merges/elides sorted scattered writes to minimise + * IO requests and maximise IO rates. + * + * @author Martyn Cutcher + * + */ +public class BufferedWrite { + final RWStore m_store; + final ByteBuffer m_data; + long m_startAddr = -1; + long m_endAddr = 0; + + long m_dataBytes = 0; + long m_dataWrites = 0; + long m_fileWrites = 0; + + public BufferedWrite(final RWStore store) throws InterruptedException { + m_store = store; + m_data = DirectBufferPool.INSTANCE.acquire(); + } + + public void write(final long offset, final ByteBuffer data, final IReopenChannel<FileChannel> opener) throws IOException { + m_dataWrites++; + + int data_len = data.remaining(); + int slot_len = m_store.getSlotSize(data_len); + + if (slot_len > m_data.remaining()) { + flush(opener); + } + + if (m_startAddr == -1) { + m_startAddr = m_endAddr = offset; + } else if (m_endAddr != offset) { + // if this is NOT a contiguous write then flush existing content + flush(opener); + m_startAddr = m_endAddr = offset; + } + m_data.put(data); + m_endAddr += slot_len; + long pos = m_endAddr - m_startAddr; + m_data.position((int) pos); + } + + public void flush(final IReopenChannel<FileChannel> opener) throws IOException { + m_dataBytes += m_data.position(); + + m_data.flip(); + FileChannelUtility.writeAll(opener, m_data, m_startAddr); + m_fileWrites++; + + m_data.position(0); + m_data.limit(m_data.capacity()); + + m_startAddr = -1; + m_endAddr = 0; + } + + public String getStats(StringBuffer buf, boolean reset) { + String ret = "BufferedWrites, data: " + m_dataWrites + ", file: " + m_fileWrites + ", bytes: " + m_dataBytes; + + if (buf != null) { + buf.append(ret + "\n"); + } + + if (reset) { + m_dataBytes = m_fileWrites = m_dataWrites = 0; + } + + return ret; + } +} Property changes on: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java 2010-09-16 21:09:42 UTC (rev 3575) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -1579,6 +1579,12 @@ * for the RW mode. Look into putting a thread pool to work on the scattered * writes. This could be part of a refactor to apply a thread pool to IOs * and related to prefetch and {@link Memoizer} behaviors. + * + * FIXME To maximize IO rates we should attempt to elide/merge contiguous + * writes. To do this can double-buffer in writeOnChannel. This also + * provides an opportunity to write the full slot size of the RWStore that + * may have advantages, particularly for an SSD, since it may avoid a + * pre-write read to populate the write sector. */ public static class FileChannelScatteredWriteCache extends WriteCache { @@ -1587,6 +1593,7 @@ */ private final IReopenChannel<FileChannel> opener; + private final BufferedWrite m_bufferedWrite; /** * @param baseOffset * An offset @@ -1596,7 +1603,8 @@ * @throws InterruptedException */ public FileChannelScatteredWriteCache(final ByteBuffer buf, final boolean useChecksum, - final boolean isHighlyAvailable, final boolean bufferHasData, final IReopenChannel<FileChannel> opener) + final boolean isHighlyAvailable, final boolean bufferHasData, final IReopenChannel<FileChannel> opener, + final BufferedWrite bufferedWrite) throws InterruptedException { super(buf, true/* scatteredWrites */, useChecksum, isHighlyAvailable, bufferHasData); @@ -1605,6 +1613,8 @@ throw new IllegalArgumentException(); this.opener = opener; + + m_bufferedWrite = bufferedWrite; } @@ -1646,13 +1656,23 @@ view.position(pos); final long offset = entry.getKey(); // offset in file to update - - nwrites += FileChannelUtility.writeAll(opener, view, offset); + if (m_bufferedWrite == null) { + nwrites += FileChannelUtility.writeAll(opener, view, offset); + } else { + m_bufferedWrite.write(offset, view, opener); + } // if (log.isInfoEnabled()) // log.info("writing to: " + offset); registerWriteStatus(offset, md.recordLength, 'W'); } + if (m_bufferedWrite != null) { + m_bufferedWrite.flush(opener); + + if (log.isTraceEnabled()) + log.trace(m_bufferedWrite.getStats(null, true)); + } + final WriteCacheCounters counters = this.counters.get(); counters.nwrite += nwrites; counters.bytesWritten += nbytes; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-09-16 21:09:42 UTC (rev 3575) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -117,6 +117,7 @@ if (hasFree()) { m_freeList.add(this); + m_freeWaiting = false; } } @@ -190,6 +191,7 @@ // added back if ((m_freeTransients == m_freeBits) && (m_freeTransients != 0)) { m_freeList.add(this); + m_freeWaiting = false; } m_freeTransients = 0; @@ -325,9 +327,7 @@ public String getStats(final AtomicLong counter) { - final StringBuilder sb = new StringBuilder("Block size : " + m_size - + " start : " + getStartAddr() + " free : " + m_freeBits - + "\r\n"); + final StringBuilder sb = new StringBuilder(getSummaryStats()); final Iterator<AllocBlock> iter = m_allocBlocks.iterator(); while (iter.hasNext()) { @@ -336,12 +336,20 @@ break; } sb.append(block.getStats(null) + "\r\n"); - counter.addAndGet(block.getAllocBits() * m_size); + if (counter != null) + counter.addAndGet(block.getAllocBits() * m_size); } return sb.toString(); } + public String getSummaryStats() { + + return"Block size : " + m_size + + " start : " + getStartAddr() + " free : " + m_freeBits + + "\r\n"; + } + public boolean verify(int addr) { if (addr >= m_startAddr && addr < m_endAddr) { @@ -372,6 +380,8 @@ return false; } + private boolean m_freeWaiting = true; + public boolean free(final int addr, final int size) { if (addr < 0) { final int offset = ((-addr) & RWStore.OFFSET_BITS_MASK) - 3; // bit adjust @@ -382,8 +392,14 @@ if (((AllocBlock) m_allocBlocks.get(block)) .freeBit(offset % nbits)) { // bit adjust - if (m_freeBits++ == 0) { + + // Only add back to the free list if at least 3000 bits avail + if (m_freeBits++ == 0 && false) { + m_freeWaiting = false; m_freeList.add(this); + } else if (m_freeWaiting && m_freeBits == 3000) { + m_freeWaiting = false; + m_freeList.add(this); } } else { m_freeTransients++; @@ -445,6 +461,13 @@ if (log.isTraceEnabled()) log.trace("Remove from free list"); m_freeList.remove(this); + m_freeWaiting = true; + + // Should have been first on list, now check for first + if (m_freeList.size() > 0) { + FixedAllocator nxt = (FixedAllocator) m_freeList.get(0); + System.out.println("Freelist head: " + nxt.getSummaryStats()); + } } addr += (count * 32 * m_bitSize); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-09-16 21:09:42 UTC (rev 3575) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -50,6 +50,7 @@ import com.bigdata.io.FileChannelUtility; import com.bigdata.io.IReopenChannel; +import com.bigdata.io.writecache.BufferedWrite; import com.bigdata.io.writecache.WriteCache; import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.CommitRecordIndex; @@ -327,6 +328,8 @@ private ReopenFileChannel m_reopener = null; + BufferedWrite m_bufferedWrite; + class WriteCacheImpl extends WriteCache.FileChannelScatteredWriteCache { public WriteCacheImpl(final ByteBuffer buf, final boolean useChecksum, @@ -335,7 +338,7 @@ throws InterruptedException { super(buf, useChecksum, m_quorum!=null&&m_quorum - .isHighlyAvailable(), bufferHasData, opener); + .isHighlyAvailable(), bufferHasData, opener, m_bufferedWrite); } @@ -379,6 +382,7 @@ * @param fileMetadataView * @param readOnly * @param quorum + * @throws InterruptedException */ public RWStore(final FileMetadataView fileMetadataView, final boolean readOnly, @@ -412,6 +416,12 @@ } catch (IOException e1) { throw new RuntimeException(e1); } + + try { + m_bufferedWrite = new BufferedWrite(this); + } catch (InterruptedException e1) { + m_bufferedWrite = null; + } int buffers = m_fmv.getFileMetadata().writeCacheBufferCount; log.warn("RWStore using writeCacheService with buffers: " + buffers); @@ -2122,6 +2132,7 @@ str.append("Allocation: " + stats[i].m_blockSize); str.append(", slots: " + stats[i].m_filledSlots + "/" + stats[i].m_reservedSlots); str.append(", storage: " + filled + "/" + reserved); + str.append(", usage: " + (filled * 100 / reserved) + "%"); str.append("\n"); } str.append("Total - file: " + convertAddr(m_fileSize) + ", slots: " + tfilledSlots + "/" + treservedSlots + ", storage: " + tfilled + "/" + treserved + "\n"); @@ -2942,4 +2953,17 @@ return ret; } + + + public int getSlotSize(int data_len) { + int i = 0; + + int ret = m_minFixedAlloc; + while (data_len > ret) { + i++; + ret = 64 * m_allocSizes[i]; + } + + return ret; + } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWWriteCacheService.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWWriteCacheService.java 2010-09-16 21:09:42 UTC (rev 3575) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWWriteCacheService.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -32,6 +32,7 @@ import org.apache.log4j.Logger; import com.bigdata.io.IReopenChannel; +import com.bigdata.io.writecache.BufferedWrite; import com.bigdata.io.writecache.WriteCache; import com.bigdata.io.writecache.WriteCacheService; import com.bigdata.io.writecache.WriteCache.FileChannelScatteredWriteCache; @@ -53,7 +54,6 @@ super(nbuffers, true/* useChecksum */, fileExtent, opener, quorum); - } /** @@ -72,7 +72,7 @@ return new FileChannelScatteredWriteCache(buf, true/* useChecksum */, highlyAvailable, bufferHasData, - (IReopenChannel<FileChannel>) opener); + (IReopenChannel<FileChannel>) opener, null); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2010-09-16 21:09:42 UTC (rev 3575) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -1780,7 +1780,7 @@ case RW: return new FileChannelScatteredWriteCache(buf, useChecksum, isHighlyAvailable, bufferHasData, - (IReopenChannel<FileChannel>) opener); + (IReopenChannel<FileChannel>) opener, null); default: throw new UnsupportedOperationException(); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWriteCache.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWriteCache.java 2010-09-16 21:09:42 UTC (rev 3575) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/io/writecache/TestWriteCache.java 2010-09-17 10:19:27 UTC (rev 3576) @@ -528,7 +528,7 @@ // ctor correct rejection tests: opener is null. try { new WriteCache.FileChannelScatteredWriteCache(buf, - useChecksum, isHighlyAvailable, bufferHasData, null/* opener */); + useChecksum, isHighlyAvailable, bufferHasData, null/* opener */, null); fail("Expected: " + IllegalArgumentException.class); } catch (IllegalArgumentException ex) { if (log.isInfoEnabled()) @@ -537,7 +537,7 @@ // allocate write cache using our buffer. final WriteCache writeCache = new WriteCache.FileChannelScatteredWriteCache( - buf, useChecksum, isHighlyAvailable, bufferHasData, opener); + buf, useChecksum, isHighlyAvailable, bufferHasData, opener, null); // verify the write cache self-reported capacity. assertEquals(DirectBufferPool.INSTANCE.getBufferCapacity() @@ -869,9 +869,9 @@ ByteBuffer data2 = getRandomData(20 * 1024); int chk2 = ChecksumUtility.threadChk.get().checksum(data2, 0/* offset */, data2.limit()); WriteCache cache1 = new WriteCache.FileChannelScatteredWriteCache(buf, true, true, - false, opener); + false, opener, null); WriteCache cache2 = new WriteCache.FileChannelScatteredWriteCache(buf2, true, true, - false, opener); + false, opener, null); // write first data buffer cache1.write(addr1, data1, chk1); @@ -976,7 +976,7 @@ // allocate write cache using our buffer. final WriteCache writeCache = new WriteCache.FileChannelScatteredWriteCache( - buf, useChecksum, isHighlyAvailable, bufferHasData, opener); + buf, useChecksum, isHighlyAvailable, bufferHasData, opener, null); /* * First write 500 records into the cache and confirm they can all be read okay This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-10-08 14:37:05
|
Revision: 3753 http://bigdata.svn.sourceforge.net/bigdata/?rev=3753&view=rev Author: thompsonbry Date: 2010-10-08 14:36:59 +0000 (Fri, 08 Oct 2010) Log Message: ----------- Modified the WriteCacheService to set open:=false at the top of close() and to trap a thrown IllegalStateException in read() and return null so that the caller will read through to the backing store if the write cache service is concurrently closed (this is per its API). Modified the TestConcurrentJournal to check for isCancelled() since the test_concurrentReaders() was running with a timeout and failing if any tasks were cancelled. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2010-10-08 12:50:48 UTC (rev 3752) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2010-10-08 14:36:59 UTC (rev 3753) @@ -226,6 +226,8 @@ * write lock prevents {@link #acquireForWriter()} when we must either reset * the {@link #current} cache buffer or change the {@link #current} * reference. E.g., {@link #flush(boolean, long, TimeUnit)}. + * <p> + * Note: {@link #read(long)} is non-blocking. It does NOT use this lock!!! */ final private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); @@ -957,6 +959,9 @@ return; } + // Closed. + open = false; + // Interrupt the write task. localWriteFuture.cancel(true/* mayInterruptIfRunning */); final Future<?> rwf = remoteWriteFuture; @@ -1031,9 +1036,6 @@ // if (haServer != null) // haServer.interrupt(); - // Closed. - open = false; - } finally { writeLock.unlock(); } @@ -1910,8 +1912,6 @@ * Not open. Return [null] rather than throwing an exception per the * contract for this implementation. */ - log.warn("Reading from closed writeCacheService"); - return null; } @@ -1934,9 +1934,17 @@ * Ask the cache buffer if it has the record still. It will not if the * cache buffer has been concurrently reset. */ + try { + return cache.read(off.longValue()); + } catch (IllegalStateException ex) { + /* + * The write cache was closed. Per the API for this method, return + * [null] so that the caller will read through to the backing store. + */ + assert !open; + return null; + } - return cache.read(off.longValue()); - } /** Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java 2010-10-08 12:50:48 UTC (rev 3752) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java 2010-10-08 14:36:59 UTC (rev 3753) @@ -1784,7 +1784,7 @@ for(Future f : futures) { - if(f.isDone()) { + if(f.isDone()&&!f.isCancelled()) { // all tasks that complete should have done so without error. f.get(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-10-13 16:56:30
|
Revision: 3789 http://bigdata.svn.sourceforge.net/bigdata/?rev=3789&view=rev Author: martyncutcher Date: 2010-10-13 16:56:24 +0000 (Wed, 13 Oct 2010) Log Message: ----------- Ensure DirectBuffer for BufferedWrites is released Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java 2010-10-13 15:24:57 UTC (rev 3788) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/BufferedWrite.java 2010-10-13 16:56:24 UTC (rev 3789) @@ -55,6 +55,10 @@ m_data = DirectBufferPool.INSTANCE.acquire(); } + public void release() throws InterruptedException { + DirectBufferPool.INSTANCE.release(m_data); + } + public int write(final long offset, final ByteBuffer data, final IReopenChannel<FileChannel> opener) throws IOException { int nwrites = 0; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-10-13 15:24:57 UTC (rev 3788) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-10-13 16:56:24 UTC (rev 3789) @@ -491,7 +491,7 @@ m_minFixedAlloc = m_allocSizes[0]*64; commitChanges(); - + } else { initfromRootBlock(); @@ -509,6 +509,10 @@ public void close() { try { + if (m_bufferedWrite != null) { + m_bufferedWrite.release(); + m_bufferedWrite = null; + } m_writeCache.close(); m_raf.close(); } catch (IOException e) { @@ -581,7 +585,8 @@ * @throws IOException */ private void initfromRootBlock() throws IOException { - m_rb = m_fmv.getRootBlock(); + // m_rb = m_fmv.getRootBlock(); + assert(m_rb != null); m_commitCounter = m_rb.getCommitCounter(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-10-13 15:24:57 UTC (rev 3788) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-10-13 16:56:24 UTC (rev 3789) @@ -960,57 +960,60 @@ */ public void test_allocationContexts() throws IOException { Journal store = (Journal) getStore(); + try { + RWStrategy bs = (RWStrategy) store.getBufferStrategy(); - RWStrategy bs = (RWStrategy) store.getBufferStrategy(); + RWStore rw = bs.getRWStore(); - RWStore rw = bs.getRWStore(); - - // JournalShadow shadow = new JournalShadow(store); + // JournalShadow shadow = new JournalShadow(store); - // Create a couple of contexts - IAllocationContext allocContext1 = new DummyAllocationContext(); - IAllocationContext allocContext2 = new DummyAllocationContext(); - - int sze = 650; - byte[] buf = new byte[sze+4]; // extra for checksum - r.nextBytes(buf); - - long addr1a = bs.write(ByteBuffer.wrap(buf), allocContext1); - long addr1b = bs.write(ByteBuffer.wrap(buf), allocContext1); - rw.detachContext(allocContext1); - - - long addr2a = bs.write(ByteBuffer.wrap(buf), allocContext2); - long addr2b = bs.write(ByteBuffer.wrap(buf), allocContext2); - rw.detachContext(allocContext2); - - // Re-establish context - long addr1c = bs.write(ByteBuffer.wrap(buf), allocContext1); - - // By detaching contexts we end up using the same allocator - assertTrue("allocator re-use", bs.getPhysicalAddress(addr1c) > bs.getPhysicalAddress(addr2b)); - - // Now, prior to commit, try deleting an uncommitted allocation - bs.delete(addr1c, allocContext1); - // and re-allocating it from the same context - long addr1d = bs.write(ByteBuffer.wrap(buf), allocContext1); + // Create a couple of contexts + IAllocationContext allocContext1 = new DummyAllocationContext(); + IAllocationContext allocContext2 = new DummyAllocationContext(); - assertTrue("re-allocation", addr1c==addr1d); + int sze = 650; + byte[] buf = new byte[sze + 4]; // extra for checksum + r.nextBytes(buf); - rw.detachContext(allocContext1); - - // Now commit - store.commit(); - - // now try deleting and re-allocating again, but in a global context - bs.delete(addr1d); // this should call deferFree - long addr1e = bs.write(ByteBuffer.wrap(buf), allocContext1); - - assertTrue("deferred-delete", addr1e != addr1d); - - // Now commit - store.commit(); + long addr1a = bs.write(ByteBuffer.wrap(buf), allocContext1); + long addr1b = bs.write(ByteBuffer.wrap(buf), allocContext1); + rw.detachContext(allocContext1); + long addr2a = bs.write(ByteBuffer.wrap(buf), allocContext2); + long addr2b = bs.write(ByteBuffer.wrap(buf), allocContext2); + rw.detachContext(allocContext2); + + // Re-establish context + long addr1c = bs.write(ByteBuffer.wrap(buf), allocContext1); + + // By detaching contexts we end up using the same allocator + assertTrue("allocator re-use", bs.getPhysicalAddress(addr1c) > bs.getPhysicalAddress(addr2b)); + + // Now, prior to commit, try deleting an uncommitted allocation + bs.delete(addr1c, allocContext1); + // and re-allocating it from the same context + long addr1d = bs.write(ByteBuffer.wrap(buf), allocContext1); + + assertTrue("re-allocation", addr1c == addr1d); + + rw.detachContext(allocContext1); + + // Now commit + store.commit(); + + // now try deleting and re-allocating again, but in a global + // context + bs.delete(addr1d); // this should call deferFree + long addr1e = bs.write(ByteBuffer.wrap(buf), allocContext1); + + assertTrue("deferred-delete", addr1e != addr1d); + + // Now commit + store.commit(); + } finally { + store.destroy(); + } + } public void test_stressAlloc() { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-10-14 16:19:29
|
Revision: 3800 http://bigdata.svn.sourceforge.net/bigdata/?rev=3800&view=rev Author: martyncutcher Date: 2010-10-14 16:19:22 +0000 (Thu, 14 Oct 2010) Log Message: ----------- Fix abort to ensure rootBlocks kept in sync and adjust stressTestAbort to reduce count until RWStore reopen can be faster Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestAbort.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-10-14 14:41:34 UTC (rev 3799) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-10-14 16:19:22 UTC (rev 3800) @@ -545,6 +545,8 @@ * Calls through to store and then to WriteCacheService.reset */ public void abort() { + m_store.checkRootBlock(m_rb); + m_store.reset(); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestAbort.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestAbort.java 2010-10-14 14:41:34 UTC (rev 3799) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestAbort.java 2010-10-14 16:19:22 UTC (rev 3800) @@ -169,7 +169,6 @@ // make sure the offset has not been changed. assertEquals(firstOffset, store.getRootBlockView() .getNextOffset()); - // write some data onto the store. for (int i = 0; i < nrecs; i++) { @@ -268,7 +267,6 @@ // verify the write. assertEquals(new byte[] { 2, 4 }, ndx .lookup(new byte[] { 1, 3 })); - } finally { store.destroy(); @@ -283,10 +281,10 @@ */ public void test_stressTestAbort() { - final int LIMIT = 100; + final int LIMIT = 10; // temporary reduction while fix to RWStore reopen + // that currently takes too long for (int i = 0; i < LIMIT; i++) { - test_abort(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-10-18 12:32:11
|
Revision: 3806 http://bigdata.svn.sourceforge.net/bigdata/?rev=3806&view=rev Author: martyncutcher Date: 2010-10-18 12:32:05 +0000 (Mon, 18 Oct 2010) Log Message: ----------- Rationalise rootBlock syncronization to handle rollback correctly, and amend test code Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractRestartSafeTestCase.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-10-18 12:03:54 UTC (rev 3805) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-10-18 12:32:05 UTC (rev 3806) @@ -447,6 +447,10 @@ // Current rootBlock is retained m_rb = rootBlock; + if (m_rb.isRootBlock0()) + m_rb0 = m_rb; + else + m_rb1 = m_rb; } @@ -525,17 +529,6 @@ m_commitLock.lock(); try { m_store.commitChanges(); // includes a force(false) - IRootBlockView rb = getRootBlock(); - - writeRootBlock(rb, ForceEnum.No); - - m_rb = rb; - - if (m_rb.isRootBlock0()) { - m_rb0 = m_rb; - } else { - m_rb1 = m_rb; - } } finally { m_commitLock.unlock(); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractRestartSafeTestCase.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractRestartSafeTestCase.java 2010-10-18 12:03:54 UTC (rev 3805) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractRestartSafeTestCase.java 2010-10-18 12:32:05 UTC (rev 3806) @@ -425,6 +425,9 @@ public void test_closeForWrites() { Journal store = (Journal) getStore(); + + if (store.getBufferStrategy() instanceof RWStrategy) + return; // void test try { Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-10-18 12:03:54 UTC (rev 3805) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-10-18 12:32:05 UTC (rev 3806) @@ -791,7 +791,7 @@ System.out.println("Now commit to disk"); - bs.commit(); + store.commit(); // Now reset - clears writeCache and reinits from disk rw.reset(); @@ -836,7 +836,7 @@ System.out.println("Now commit to disk"); - bs.commit(); + store.commit(); // Now reset - clears writeCache and reinits from disk rw.reset(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-11-01 12:52:07
|
Revision: 3852 http://bigdata.svn.sourceforge.net/bigdata/?rev=3852&view=rev Author: martyncutcher Date: 2010-11-01 12:52:00 +0000 (Mon, 01 Nov 2010) Log Message: ----------- 1) Change RWStrategy to pass the Journal reference on commit to remove need to set LocalTransactionService 2) Change deferred free to write to PSOutputStream to avoid maintaining inmemory references. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -628,7 +628,7 @@ } /** The default is a NOP. */ - public void commit() { + public void commit(IJournal journal) { // NOP for WORM. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -1045,8 +1045,6 @@ ResourceManager.openJournal(getFile() == null ? null : getFile().toString(), size(), getBufferStrategy() .getBufferMode()); - this._bufferStrategy.setCommitRecordIndex(_commitRecordIndex); - } finally { lock.unlock(); @@ -2103,8 +2101,6 @@ // clear reference and reload from the store. _commitRecordIndex = _getCommitRecordIndex(); - _bufferStrategy.setCommitRecordIndex(_commitRecordIndex); - // clear the array of committers. _committers = new ICommitter[_committers.length]; @@ -2358,7 +2354,7 @@ * until commit, leading to invalid addresses for recent store * allocations. */ - _bufferStrategy.commit(); + _bufferStrategy.commit(this); /* * next offset at which user data would be written. @@ -2875,7 +2871,7 @@ * {@link #getCommitRecord(long)} to obtain a distinct instance * suitable for read-only access. */ - protected CommitRecordIndex getCommitRecordIndex() { + public CommitRecordIndex getCommitRecordIndex() { final ReadLock lock = _fieldReadWriteLock.readLock(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -216,8 +216,9 @@ * A method that removes assumptions of how a specific strategy commits data. For most strategies the action is void * since the client WORM DISK strategy writes data as allocated. For the Read Write Strategy more data must be managed * as part of the protocol outside of the RootBlock, and this is the method that triggers that management. + * @param abstractJournal */ - public void commit(); + public void commit(IJournal journal); /** * A method that requires the implementation to discard its buffered write @@ -258,29 +259,4 @@ */ public boolean useChecksums(); - /** - * Needed to enable transaction support for standalone buffer strategies. - * - * The WORMStrategy does not need this since no data is ever deleted, but - * the RWStrategy must manage deletions such that no data is deleted until - * it can be guaranteed not to be accessed by existing transactions. - * - * @param localTransactionManager - * The transaction manager for the owning Journal - */ - public void setTransactionManager(AbstractLocalTransactionManager localTransactionManager); - - - /** - * Needed to enable transaction support for standalone buffer strategies. - * - * The WORMStrategy does not need this since no data is ever deleted, but - * the RWStrategy must manage deletions and needs access to the historical - * commitRecords which reference the blocks of deferred deleted addresses. - * - * @param commitRecordIndex - * The CommitRecordIndex for the owning Journal - */ - public void setCommitRecordIndex(CommitRecordIndex commitRecordIndex); - } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -221,10 +221,8 @@ concurrencyManager = new ConcurrencyManager(properties, localTransactionManager, this); - getBufferStrategy().setTransactionManager(localTransactionManager); + } - } - // public void init() { // // super.init(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; +import java.nio.channels.ClosedByInterruptException; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.locks.ReentrantLock; @@ -525,10 +526,10 @@ * * Must pass in earliestTxnTime to commitChanges to enable */ - public void commit() { + public void commit(IJournal journal) { m_commitLock.lock(); try { - m_store.commitChanges(); // includes a force(false) + m_store.commitChanges((Journal) journal); // includes a force(false) } finally { m_commitLock.unlock(); } @@ -546,6 +547,12 @@ public void force(boolean metadata) { try { m_store.flushWrites(metadata); + } catch (ClosedByInterruptException e) { + m_needsReopen = true; + + reopen(); // FIXME + + throw new RuntimeException(e); } catch (IOException e) { m_needsReopen = true; @@ -716,11 +723,6 @@ } - public void setTransactionManager(AbstractLocalTransactionManager localTransactionManager) { - this.localTransactionManager = localTransactionManager; - m_store.setTransactionService((JournalTransactionService) localTransactionManager.getTransactionService()); - } - public long getPhysicalAddress(long addr) { int rwaddr = decodeAddr(addr); @@ -737,9 +739,4 @@ public long saveDeleteBlocks() { return m_store.saveDeferrals(); } - - public void setCommitRecordIndex(CommitRecordIndex commitRecordIndex) { - m_store.setCommitRecordIndex(commitRecordIndex); - } - } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -158,28 +158,29 @@ * resets private state variables for reuse of stream **/ void init(IStore store, int maxAlloc, IAllocationContext context) { + m_store = store; + m_context = context; + + m_blobThreshold = maxAlloc-4; // allow for checksum + if (m_buf == null || m_buf.length != m_blobThreshold) + m_buf = new byte[m_blobThreshold]; + + reset(); + } + + public void reset() { m_isSaved = false; m_headAddr = 0; m_prevAddr = 0; m_count = 0; m_bytesWritten = 0; - m_store = store; m_isSaved = false; - // m_blobThreshold = m_store.bufferChainOffset(); - m_blobThreshold = maxAlloc-4; // allow for checksum - m_buf = new byte[maxAlloc-4]; m_blobHeader = null; m_blobHdrIdx = 0; - - m_context = context; + } - - // FIXME: if autocommit then we should provide start/commit via init and save - // m_store.startTransaction(); - } - /**************************************************************** * write a single byte * Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -52,6 +52,7 @@ import com.bigdata.io.IReopenChannel; import com.bigdata.io.writecache.BufferedWrite; import com.bigdata.io.writecache.WriteCache; +import com.bigdata.journal.Journal; import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.CommitRecordIndex; import com.bigdata.journal.ForceEnum; @@ -323,8 +324,7 @@ private static final int MAX_DEFERRED_FREE = 4094; // fits in 16k block volatile long m_lastDeferredReleaseTime = 23; // zero is invalid time final ArrayList<Integer> m_currentTxnFreeList = new ArrayList<Integer>(); - - volatile long deferredFreeCount = 0; + final PSOutputStream m_deferredFreeOut; private ReopenFileChannel m_reopener = null; @@ -490,7 +490,7 @@ m_maxFixedAlloc = m_allocSizes[m_allocSizes.length-1]*64; m_minFixedAlloc = m_allocSizes[0]*64; - commitChanges(); + commitChanges(null); } else { @@ -502,6 +502,7 @@ assert m_maxFixedAlloc > 0; + m_deferredFreeOut = PSOutputStream.getNew(this, m_maxFixedAlloc, null); } catch (IOException e) { throw new StorageTerminalError("Unable to initialize store", e); } @@ -1213,8 +1214,6 @@ private volatile long m_maxAllocation = 0; private volatile long m_spareAllocation = 0; - - private CommitRecordIndex m_commitRecordIndex; public int alloc(final int size, IAllocationContext context) { if (size > m_maxFixedAlloc) { @@ -1569,7 +1568,7 @@ return "RWStore " + s_version; } - public void commitChanges() { + public void commitChanges(Journal journal) { checkCoreAllocations(); // take allocation lock to prevent other threads allocating during commit @@ -1577,7 +1576,7 @@ try { - checkDeferredFrees(true); // free now if possible + checkDeferredFrees(true, journal); // free now if possible // Allocate storage for metaBits long oldMetaBits = m_metaBitsAddr; @@ -1653,30 +1652,26 @@ * Called prior to commit, so check whether storage can be freed and then * whether the deferredheader needs to be saved. */ - private void checkDeferredFrees(boolean freeNow) { - if (freeNow) checkFreeable(); - - // Commit can be called prior to Journal initialisation, in which case - // the commitRecordIndex will not be set. - if (m_commitRecordIndex == null) { - return; + public void checkDeferredFrees(boolean freeNow, Journal journal) { + if (journal != null) { + final JournalTransactionService transactionService = (JournalTransactionService) journal.getLocalTransactionManager().getTransactionService(); + + // Commit can be called prior to Journal initialisation, in which case + // the commitRecordIndex will not be set. + final CommitRecordIndex commitRecordIndex = journal.getCommitRecordIndex(); + + long latestReleasableTime = System.currentTimeMillis(); + + if (transactionService != null) { + latestReleasableTime -= transactionService.getMinReleaseAge(); + } + + Iterator<ICommitRecord> records = commitRecordIndex.getCommitRecords(m_lastDeferredReleaseTime, latestReleasableTime); + + freeDeferrals(records); } - - long latestReleasableTime = System.currentTimeMillis(); - - if (m_transactionService != null) { - latestReleasableTime -= m_transactionService.getMinReleaseAge(); - } - - Iterator<ICommitRecord> records = m_commitRecordIndex.getCommitRecords(m_lastDeferredReleaseTime, latestReleasableTime); - - freeDeferrals(records); } - - public void setCommitRecordIndex(CommitRecordIndex commitRecordIndex) { - m_commitRecordIndex = commitRecordIndex; - } /** * * @return conservative requirement for metabits storage, mindful that the @@ -2654,45 +2649,39 @@ * * The deferred list is checked on AllocBlock and prior to commit. * - * There is also a possibility to check for deferral at this point, since - * we are passed both the currentCommitTime - against which this free - * will be deferred and the earliest tx start time against which we - * can check to see if + * DeferredFrees are written to the deferred PSOutputStream */ public void deferFree(int rwaddr, int sze) { m_deferFreeLock.lock(); try { - deferredFreeCount++; - m_currentTxnFreeList.add(rwaddr); + m_deferredFreeOut.writeInt(rwaddr); final Allocator alloc = getBlockByAddress(rwaddr); if (alloc instanceof BlobAllocator) { - m_currentTxnFreeList.add(sze); + m_deferredFreeOut.writeInt(sze); } - - // every so many deferrals, check for free - if (false && deferredFreeCount % 1000 == 0) { - checkFreeable(); - } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } finally { m_deferFreeLock.unlock(); } } - private void checkFreeable() { - if (m_transactionService == null) { + private void checkFreeable(final JournalTransactionService transactionService) { + if (transactionService == null) { return; } try { - Long freeTime = m_transactionService.tryCallWithLock(new Callable<Long>() { + Long freeTime = transactionService.tryCallWithLock(new Callable<Long>() { public Long call() throws Exception { long now = System.currentTimeMillis(); - long earliest = m_transactionService.getEarliestTxStartTime(); - long aged = now - m_transactionService.getMinReleaseAge(); + long earliest = transactionService.getEarliestTxStartTime(); + long aged = now - transactionService.getMinReleaseAge(); - if (m_transactionService.getActiveCount() == 0) { + if (transactionService.getActiveCount() == 0) { return aged; } else { return aged < earliest ? aged : earliest; @@ -2700,8 +2689,6 @@ } }, 5L, TimeUnit.MILLISECONDS); - - freeCurrentDeferrals(freeTime); } catch (RuntimeException e) { // fine, will try again later } catch (Exception e) { @@ -2711,38 +2698,6 @@ /** - * Frees all storage deferred against a txn release time less than that - * passed in. - * - * @param txnRelease - the max release time - */ - protected void freeCurrentDeferrals(long txnRelease) { - - m_deferFreeLock.lock(); - try { - if (m_rb.getLastCommitTime() <= txnRelease) { -// System.out.println("freeCurrentDeferrals"); - final Iterator<Integer> curdefers = m_currentTxnFreeList.iterator(); - while (curdefers.hasNext()) { - final int rwaddr = curdefers.next(); - Allocator alloc = getBlock(rwaddr); - if (alloc instanceof BlobAllocator) { - // if this is a Blob then the size is required - assert curdefers.hasNext(); - - immediateFree(rwaddr, curdefers.next()); - } else { - immediateFree(rwaddr, 0); // size ignored for FixedAllocators - } - } - m_currentTxnFreeList.clear(); - } - } finally { - m_deferFreeLock.unlock(); - } - } - - /** * Writes the content of currentTxnFreeList to the store. * * These are the current buffered frees that have yet been saved into @@ -2751,39 +2706,27 @@ * @return the address of the deferred addresses saved on the store */ public long saveDeferrals() { - final byte[] buf; m_deferFreeLock.lock(); try { - int addrCount = m_currentTxnFreeList.size(); - - if (addrCount == 0) { - return 0L; + if (m_deferredFreeOut.getBytesWritten() == 0) { + return 0; } + m_deferredFreeOut.writeInt(0); // terminate! + int outlen = m_deferredFreeOut.getBytesWritten(); + + long addr = m_deferredFreeOut.save(); + + addr <<= 32; + addr += outlen; + + m_deferredFreeOut.reset(); - buf = new byte[4 * (addrCount + 1)]; - ByteBuffer out = ByteBuffer.wrap(buf); - out.putInt(addrCount); - for (int i = 0; i < addrCount; i++) { - out.putInt(m_currentTxnFreeList.get(i)); - } - - // now we've saved it to the store, clear the list - m_currentTxnFreeList.clear(); - + return addr; + } catch (IOException e) { + throw new RuntimeException("Cannot write to deferred free", e); } finally { m_deferFreeLock.unlock(); } - - long rwaddr = alloc(buf, buf.length, null); - if (log.isTraceEnabled()) { - long paddr = physicalAddress((int) rwaddr); - log.trace("Saving deferred free block at " + paddr); - } - - rwaddr <<= 32; - rwaddr += buf.length; - - return rwaddr; } /** @@ -2802,19 +2745,21 @@ final DataInputStream strBuf = new DataInputStream(new ByteArrayInputStream(buf)); m_allocationLock.lock(); try { - int addrs = strBuf.readInt(); + int nxtAddr = strBuf.readInt(); - while (addrs-- > 0) { // while (false && addrs-- > 0) { - int nxtAddr = strBuf.readInt(); + while (nxtAddr != 0) { // while (false && addrs-- > 0) { Allocator alloc = getBlock(nxtAddr); if (alloc instanceof BlobAllocator) { - assert addrs > 0; // a Blob address MUST have a size - --addrs; - immediateFree(nxtAddr, strBuf.readInt()); + int bloblen = strBuf.readInt(); + assert bloblen > 0; // a Blob address MUST have a size + + immediateFree(nxtAddr, bloblen); } else { immediateFree(nxtAddr, 0); // size ignored for FreeAllocators } + + nxtAddr = strBuf.readInt(); } m_lastDeferredReleaseTime = lastReleaseTime; } catch (IOException e) { @@ -2840,11 +2785,6 @@ } } - private JournalTransactionService m_transactionService = null; - public void setTransactionService(final JournalTransactionService transactionService) { - this.m_transactionService = transactionService; - } - /** * The ContextAllocation object manages a freeList of associated allocators * and an overall list of allocators. When the context is detached, all Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -314,7 +314,7 @@ } else if (store instanceof RWStrategy) { RWStrategy rws = (RWStrategy)store; - rws.commit(); + rws.commit(null); } try { Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -240,7 +240,7 @@ properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - return new Journal(properties).getBufferStrategy(); + return new Journal(properties); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-01 12:32:36 UTC (rev 3851) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-01 12:52:00 UTC (rev 3852) @@ -849,8 +849,10 @@ // since deferred frees, we must commit in order to ensure the // address in invalid, indicating it is available for - bs.commit(); + store.commit(); + rw.checkDeferredFrees(true, store); + try { rdBuf = bs.read(faddr); // should fail with illegal state throw new RuntimeException("Fail"); @@ -1147,7 +1149,8 @@ properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - return new Journal(properties).getBufferStrategy(); + // return new Journal(properties).getBufferStrategy(); + return new Journal(properties); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-02 19:00:39
|
Revision: 3873 http://bigdata.svn.sourceforge.net/bigdata/?rev=3873&view=rev Author: thompsonbry Date: 2010-11-02 19:00:31 +0000 (Tue, 02 Nov 2010) Log Message: ----------- A bunch of edits to clean up RWStrategy and RWStore. There is a deadlock which can be demonstrated using StressTestConcurrentUnisolatedIndices and which results in a deadlock. It seems like there are probably too many distinct locks -- or that the m_allocationLock needs to be acquired before the m_deferFreeLock (which probably means that the m_deferFreeLock is redundant). Either way, this should be easy enough to clean up. This thread is holding the Journal's internal lock, holding the RWStore#m_deferFreeLock (in saveDeferrals), and waiting on RWStore#m_allocationLock (in alloc()): com.bigdata.journal.ConcurrencyManager.writeService14 [WAITING] CPU time: 0:00 java.util.concurrent.locks.ReentrantLock.lock() com.bigdata.rwstore.RWStore.alloc(int, IAllocationContext) com.bigdata.rwstore.RWStore.alloc(byte[], int, IAllocationContext) com.bigdata.rwstore.PSOutputStream.save() com.bigdata.rwstore.RWStore.saveDeferrals() com.bigdata.journal.RWStrategy.saveDeleteBlocks() com.bigdata.journal.DeleteBlockCommitter.handleCommit(long) com.bigdata.journal.AbstractJournal.notifyCommitters(long) com.bigdata.journal.AbstractJournal.commitNow(long) com.bigdata.journal.AbstractJournal.commit() com.bigdata.journal.WriteExecutorService.commit(boolean) com.bigdata.journal.WriteExecutorService.groupCommit() com.bigdata.journal.WriteExecutorService.afterTask(AbstractTask, Throwable) com.bigdata.journal.AbstractTask.doUnisolatedReadWriteTask() com.bigdata.journal.AbstractTask.call2() com.bigdata.journal.AbstractTask.call() java.util.concurrent.FutureTask.run() com.bigdata.concurrent.NonBlockingLockManagerWithNewDesign$LockFutureTask.run() java.lang.Thread.run() This thread is holding m_allocationLock (in free()) and waiting on m_deferFreeLock: com.bigdata.journal.ConcurrencyManager.writeService7 [WAITING] CPU time: 0:00 java.util.concurrent.locks.ReentrantLock.lock() com.bigdata.rwstore.RWStore.deferFree(int, int) com.bigdata.rwstore.RWStore.free(long, int, IAllocationContext) com.bigdata.journal.RWStrategy.delete(long, IAllocationContext) com.bigdata.journal.RWStrategy.delete(long) com.bigdata.journal.AbstractJournal.delete(long) com.bigdata.btree.Node.replaceChildRef(long, AbstractNode) com.bigdata.btree.AbstractNode.copyOnWrite(long) com.bigdata.btree.AbstractNode.copyOnWrite() com.bigdata.btree.Leaf.insert(byte[], byte[], boolean, long, Tuple) com.bigdata.btree.Node.insert(byte[], byte[], boolean, long, Tuple) com.bigdata.btree.Node.insert(byte[], byte[], boolean, long, Tuple) com.bigdata.btree.AbstractBTree.insert(byte[], byte[], boolean, long, Tuple) com.bigdata.btree.AbstractBTree.insert(byte[], byte[]) com.bigdata.journal.StressTestConcurrentUnisolatedIndices$WriteTask.doTask() com.bigdata.journal.AbstractTask$InnerWriteServiceCallable.call() com.bigdata.journal.AbstractTask.doUnisolatedReadWriteTask() com.bigdata.journal.AbstractTask.call2() com.bigdata.journal.AbstractTask.call() java.util.concurrent.FutureTask.run() com.bigdata.concurrent.NonBlockingLockManagerWithNewDesign$LockFutureTask.run() java.lang.Thread.run() Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentTx.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2010-11-02 17:46:33 UTC (rev 3872) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2010-11-02 19:00:31 UTC (rev 3873) @@ -325,10 +325,10 @@ int addrsUsedCurs = 0; final char[] addrActions = new char[addrsUsed.length]; final int[] addrLens = new int[addrsUsed.length]; -*/ final long[] addrsUsed = null; - int addrsUsedCurs = 0; - final char[] addrActions = null; - final int[] addrLens = null; +*/ private final long[] addrsUsed = null; + private int addrsUsedCurs = 0; + private final char[] addrActions = null; + private final int[] addrLens = null; /** * The current file extent. @@ -1989,7 +1989,7 @@ * An array of writeCache actions is maintained that can be used * to provide a breadcrumb of how that address has been written, saved, * freed or removed. - * + * <p> * Write errors often show up as a checksum error, so the length of * data written to the address cab be crucial information in determining the * root of any problem. @@ -2002,9 +2002,9 @@ return "No WriteCache debug info"; } - StringBuffer ret = new StringBuffer(); - // first see if address was ever written - boolean written = false; + final StringBuffer ret = new StringBuffer(); +// // first see if address was ever written +// boolean written = false; for (int i = 0; i < addrsUsed.length; i++) { if (i == addrsUsedCurs) { ret.append("|...|"); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2010-11-02 17:46:33 UTC (rev 3872) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2010-11-02 19:00:31 UTC (rev 3873) @@ -28,7 +28,6 @@ import java.nio.ByteBuffer; import com.bigdata.counters.CounterSet; -import com.bigdata.io.writecache.WriteCacheService; import com.bigdata.rawstore.IAddressManager; import com.bigdata.rawstore.IMRMW; import com.bigdata.rawstore.IRawStore; @@ -204,55 +203,65 @@ public IAddressManager getAddressManager(); /** - * A method that removes assumptions of how a specific strategy determines whether a transaction commit is required. + * A method that removes assumptions of how a specific strategy determines + * whether a transaction commit is required. * * @param block - * The root block held by the client, can be checked against the state of the Buffer Strategy + * The root block held by the client, can be checked against the + * state of the Buffer Strategy * @return whether any modification has occurred. */ - public boolean requiresCommit(IRootBlockView block); + public boolean requiresCommit(IRootBlockView block); /** - * A method that removes assumptions of how a specific strategy commits data. For most strategies the action is void - * since the client WORM DISK strategy writes data as allocated. For the Read Write Strategy more data must be managed - * as part of the protocol outside of the RootBlock, and this is the method that triggers that management. - * @param abstractJournal + * A method that removes assumptions of how a specific strategy commits + * data. For most strategies the action is void since the client WORM DISK + * strategy writes data as allocated. For the Read Write Strategy more data + * must be managed as part of the protocol outside of the RootBlock, and + * this is the method that triggers that management. + * + * @param abstractJournal */ - public void commit(IJournal journal); + public void commit(IJournal journal); /** * A method that requires the implementation to discard its buffered write * set (if any). The caller is responsible for any necessary synchronization * as part of the abort protocol. */ - public void abort(); - - /** - * The RWStrategy requires meta allocation info in the root block, this method is the hook to enable access. - * The metaStartAddr is the address in the file where the allocation blocks are stored. - * - * @return the metaStartAddr for the root block if any - */ - public long getMetaStartAddr(); - /** - * The RWStrategy requires meta allocation info in the root block, this method is the hook to enable access. - * The metaBitsAddr is the address in the file where the metaBits that control the allocation of the allocation - * blocks themselves is stored. - * - * @return the metaBitsAddr for the root block if any - */ - public long getMetaBitsAddr(); - /** - * @return the number of bits available in the address to define offset - */ + public void abort(); - public int getOffsetBits(); - /** - * @return the maximum record size supported by this strategy - */ - public int getMaxRecordSize(); + /** + * The RWStrategy requires meta allocation info in the root block, this + * method is the hook to enable access. The metaStartAddr is the address in + * the file where the allocation blocks are stored. + * + * @return the metaStartAddr for the root block if any + */ + public long getMetaStartAddr(); /** + * The RWStrategy requires meta allocation info in the root block, this + * method is the hook to enable access. The metaBitsAddr is the address in + * the file where the metaBits that control the allocation of the allocation + * blocks themselves is stored. + * + * @return the metaBitsAddr for the root block if any + */ + public long getMetaBitsAddr(); + + /** + * @return the number of bits available in the address to define offset + */ + + public int getOffsetBits(); + + /** + * @return the maximum record size supported by this strategy + */ + public int getMaxRecordSize(); + + /** * Return <code>true</code> if the store uses per-record checksums. When * <code>true</code>, an additional 4 bytes are written after the record on * the disk. Those bytes contain the checksum of the record. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-02 17:46:33 UTC (rev 3872) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-02 19:00:31 UTC (rev 3873) @@ -24,15 +24,12 @@ package com.bigdata.journal; -import java.io.DataInput; -import java.io.DataOutput; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.ClosedByInterruptException; import java.util.UUID; -import java.util.concurrent.Callable; import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; @@ -45,7 +42,6 @@ import com.bigdata.rawstore.IAddressManager; import com.bigdata.rwstore.IAllocationContext; import com.bigdata.rwstore.RWStore; -import com.bigdata.service.AbstractTransactionService; import com.bigdata.util.ChecksumUtility; /** @@ -68,8 +64,9 @@ * @author Martyn Cutcher */ public class RWStrategy extends AbstractRawStore implements IBufferStrategy, IHABufferStrategy { - protected static final Logger log = Logger.getLogger(RWStrategy.class); + private static final transient Logger log = Logger.getLogger(RWStrategy.class); + final private FileMetadata m_fileMetadata; final private Quorum<?,?> m_environment; @@ -88,14 +85,20 @@ private volatile IRootBlockView m_rb; private volatile IRootBlockView m_rb0; private volatile IRootBlockView m_rb1; - - final ReentrantLock m_commitLock = new ReentrantLock(); - + /** - * Access to the transaction manager of any owning Journal, needed by - * RWStrategy to manager deleted data. + * @todo The use of this lock is suspicious. It is only used by + * {@link #commit(IJournal)} and that method is invoked by the + * {@link AbstractJournal#commitNow(long)} which is already protected + * by a lock. */ - private AbstractLocalTransactionManager localTransactionManager = null; + private final ReentrantLock m_commitLock = new ReentrantLock(); + +// /** +// * Access to the transaction manager of any owning Journal, needed by +// * RWStrategy to manager deleted data. +// */ +// private AbstractLocalTransactionManager localTransactionManager = null; // CounterSet m_counters = new CounterSet(); @@ -125,16 +128,26 @@ } /** + * Return a copy of the current {@link IRootBlockView}. + * * @param rb0 - * @return + * When <code>true</code> the view will be flagged as root block + * ZERO (0). Otherwise it is flagged as root block ONE (1). + * + * @return The {@link IRootBlockView}. */ - IRootBlockView copyRootBlock(boolean rb0) { - IRootBlockView rbv = new RootBlockView(rb0, m_rb.getOffsetBits(), m_rb.getNextOffset(), m_rb.getFirstCommitTime(), m_rb.getLastCommitTime(), - m_rb.getCommitCounter(), m_rb.getCommitRecordAddr(), m_rb.getCommitRecordIndexAddr(), m_fileMetadata.rootBlock.getUUID(), - m_rb.getQuorumToken(), - m_rb.getMetaStartAddr(), m_rb.getMetaBitsAddr(), StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), m_rb.getCloseTime(), - s_ckutil); + private IRootBlockView copyRootBlock(final boolean rb0) { + final IRootBlockView rbv = new RootBlockView(rb0, m_rb.getOffsetBits(), + m_rb.getNextOffset(), m_rb.getFirstCommitTime(), m_rb + .getLastCommitTime(), m_rb.getCommitCounter(), m_rb + .getCommitRecordAddr(), + m_rb.getCommitRecordIndexAddr(), m_fileMetadata.rootBlock + .getUUID(), m_rb.getQuorumToken(), m_rb + .getMetaStartAddr(), m_rb.getMetaBitsAddr(), + StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), + m_rb.getCloseTime(), s_ckutil); + return rbv; } @@ -192,14 +205,19 @@ return m_fileMetadata.raf; } - public IRootBlockView newRootBlockView(boolean rootBlock0, int offsetBits, long nextOffset, - long firstCommitTime, long lastCommitTime, long commitCounter, long commitRecordAddr, - long commitRecordIndexAddr, long metaStartAddr, long metaBitsAddr, long closeTime) { + public IRootBlockView newRootBlockView(boolean rootBlock0, + int offsetBits, long nextOffset, long firstCommitTime, + long lastCommitTime, long commitCounter, long commitRecordAddr, + long commitRecordIndexAddr, long metaStartAddr, + long metaBitsAddr, long closeTime) { - IRootBlockView rbv = new RootBlockView(rootBlock0, offsetBits, nextOffset, firstCommitTime, lastCommitTime, - commitCounter, commitRecordAddr, commitRecordIndexAddr, m_fileMetadata.rootBlock.getUUID(), -1 /* FIXME: quorumToken */, - metaStartAddr, metaBitsAddr, StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), closeTime, - s_ckutil); + final IRootBlockView rbv = new RootBlockView(rootBlock0, + offsetBits, nextOffset, firstCommitTime, lastCommitTime, + commitCounter, commitRecordAddr, commitRecordIndexAddr, + m_fileMetadata.rootBlock.getUUID(), + -1 /* FIXME: quorumToken */, metaStartAddr, metaBitsAddr, + StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), + closeTime, s_ckutil); // writeRootBlock(rbv, ForceEnum.Force); // not sure if this is really needed now! @@ -211,17 +229,19 @@ } } - public ByteBuffer readRootBlock(boolean rootBlock0) { - checkReopen(); + public ByteBuffer readRootBlock(final boolean rootBlock0) { + + checkReopen(); IRootBlockView rbv = rootBlock0 ? m_rb0 : m_rb1; return rbv.asReadOnlyBuffer(); } - public ByteBuffer read(long addr) { - checkReopen(); + public ByteBuffer read(final long addr) { + checkReopen(); + int rwaddr = decodeAddr(addr); int sze = decodeSize(addr); @@ -239,12 +259,15 @@ return ByteBuffer.wrap(buf, 0, sze); } - public long write(ByteBuffer data) { - return write(data, null); + public long write(final ByteBuffer data) { + + return write(data, null); + } - public long write(ByteBuffer data, IAllocationContext context) { - checkReopen(); + public long write(final ByteBuffer data, final IAllocationContext context) { + + checkReopen(); if (data == null) { throw new IllegalArgumentException(); @@ -291,7 +314,7 @@ // return encodeAddr(m_store.alloc(nbytes), nbytes); // } - private long encodeAddr(long alloc, int nbytes) { + private long encodeAddr(long alloc, final int nbytes) { alloc <<= 32; alloc += nbytes; @@ -304,52 +327,70 @@ return (int) addr; } - private int decodeSize(long addr) { + private int decodeSize(final long addr) { return (int) (addr & 0xFFFFFFFF); } - public void delete(long addr) { - delete(addr, null); + public void delete(final long addr) { + + delete(addr, null/* IAllocationContext */); + } /** * Must check whether there are existing transactions which may access * this data, and if not free immediately, otherwise defer. */ - public void delete(long addr, IAllocationContext context) { + public void delete(final long addr, final IAllocationContext context) { final int rwaddr = decodeAddr(addr); final int sze = decodeSize(addr); m_store.free(rwaddr, sze, context); + } - public void detachContext(IAllocationContext context) { - m_store.detachContext(context); + public void detachContext(final IAllocationContext context) { + + m_store.detachContext(context); + } - + /* + * FIXME Reconcile this class with the methods on the outer class. + */ public static class RWAddressManager implements IAddressManager { - public int getByteCount(long addr) { - return (int) addr & 0xFFFFFF; + public int getByteCount(final long addr) { + + return (int) addr & 0xFFFFFF; + } - public long getOffset(long addr) { - return -(addr >> 32); + public long getOffset(final long addr) { + + return -(addr >> 32); + } - public long toAddr(int nbytes, long offset) { - offset <<= 32; + public long toAddr(final int nbytes, long offset) { + + offset <<= 32; return offset + nbytes; + } - public String toString(long addr) { - return "{off="+getOffset(addr)+",len="+getByteCount(addr)+"}"; + public String toString(final long addr) { + + return "{off=" + getOffset(addr) + ",len=" + getByteCount(addr) + + "}"; + } + } - IAddressManager m_am = new RWAddressManager(); + + final private IAddressManager m_am = new RWAddressManager(); public IAddressManager getAddressManager() { return m_am; @@ -382,9 +423,9 @@ return 0; } - long m_initialExtent = 0; + private long m_initialExtent = 0; - private boolean m_needsReopen = false; + private volatile boolean m_needsReopen = false; public long getInitialExtent() { return m_initialExtent; @@ -485,19 +526,33 @@ } public void deleteResources() { - if (m_fileMetadata.raf != null && m_fileMetadata.raf.getChannel().isOpen()) { - throw new IllegalStateException("Backing store is open"); - } - if (m_fileMetadata.file.exists()) { - try { - if (!m_fileMetadata.file.delete()) { - log.warn("Unable to delete file: " + m_fileMetadata.file); - } - } catch (SecurityException e) { - log.warn("Problem deleting file", e); - } - } + if (m_fileMetadata.raf != null + && m_fileMetadata.raf.getChannel().isOpen()) { + + throw new IllegalStateException("Backing store is open: " + + m_fileMetadata.file); + + } + + if (m_fileMetadata.file.exists()) { + + try { + + if (!m_fileMetadata.file.delete()) { + + log.warn("Unable to delete file: " + m_fileMetadata.file); + + } + + } catch (SecurityException e) { + + log.warn("Problem deleting file", e); + + } + + } + } public void destroy() { @@ -515,10 +570,18 @@ } public IRootBlockView getRootBlock() { - return m_fmv.newRootBlockView(! m_rb.isRootBlock0(), m_rb.getOffsetBits(), getNextOffset(), - m_rb.getFirstCommitTime(), m_rb.getLastCommitTime(), m_rb.getCommitCounter(), - m_rb.getCommitRecordAddr(), m_rb.getCommitRecordIndexAddr(), getMetaStartAddr(), getMetaBitsAddr(), m_rb.getCloseTime() ); - + return m_fmv.newRootBlockView(!m_rb.isRootBlock0(), // + m_rb.getOffsetBits(),// + getNextOffset(), // + m_rb.getFirstCommitTime(),// + m_rb.getLastCommitTime(), // + m_rb.getCommitCounter(),// + m_rb.getCommitRecordAddr(), // + m_rb.getCommitRecordIndexAddr(), // + getMetaStartAddr(),// + getMetaBitsAddr(), // + m_rb.getCloseTime()// + ); } /** @@ -526,7 +589,7 @@ * * Must pass in earliestTxnTime to commitChanges to enable */ - public void commit(IJournal journal) { + public void commit(final IJournal journal) { m_commitLock.lock(); try { m_store.commitChanges((Journal) journal); // includes a force(false) @@ -544,7 +607,7 @@ m_store.reset(); } - public void force(boolean metadata) { + public void force(final boolean metadata) { try { m_store.flushWrites(metadata); } catch (ClosedByInterruptException e) { @@ -572,7 +635,8 @@ log.warn("Request to reopen store after interrupt"); m_store.close(); - m_fileMetadata.raf = new RandomAccessFile(m_fileMetadata.file, m_fileMetadata.fileMode); + m_fileMetadata.raf = new RandomAccessFile(m_fileMetadata.file, + m_fileMetadata.fileMode); m_store = new RWStore(m_fmv, false, m_environment); // never read-only for now m_needsReopen = false; m_open = true; @@ -592,11 +656,19 @@ return m_fileMetadata.raf; } - public IResourceMetadata getResourceMetadata() { - // TODO Auto-generated method stub - return null; - } - + + /** + * Not supported - this is available on the {@link AbstractJournal}. + * + * @throws UnsupportedOperationException + * always + */ + public IResourceMetadata getResourceMetadata() { + + throw new UnsupportedOperationException(); + + } + public UUID getUUID() { return m_fileMetadata.rootBlock.getUUID(); } @@ -631,25 +703,14 @@ return addr >> 32; } - public void packAddr(DataOutput out, long addr) throws IOException { - // TODO Auto-generated method stub - - } - - public long toAddr(int nbytes, long offset) { + public long toAddr(final int nbytes, final long offset) { return (offset << 32) + nbytes; } - public String toString(long addr) { - // TODO Auto-generated method stub - return null; + public String toString(final long addr) { + return m_am.toString(addr); } - public long unpackAddr(DataInput in) throws IOException { - // TODO Auto-generated method stub - return 0; - } - /** * The state of the provided block is not relevant since it does not hold * information on recent allocations (the meta allocations will only effect the Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-02 17:46:33 UTC (rev 3872) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-02 19:00:31 UTC (rev 3873) @@ -35,11 +35,10 @@ import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -70,128 +69,130 @@ /** * Storage class - * - * Author: Martyn Cutcher - * + * <p> * Provides an interface to allocating storage within a disk file. - * + * <p> * Essentially provides a DiskMalloc interface. - * + * <p> * In addition to the DiskMalloc/ReAlloc mechanism, a single root address can be * associated. This can be used when opening an existing storage file to * retrieve some management object - such as an object manager! - * + * <p> * The allocator also support atomic update via a simple transaction mechanism. - * + * <p> * Updates are normally committed immediately, but by using startTransaction and * commitTransaction, the previous state of the store is retained until the * moment of commitment. - * - * It would also be possible to add some journalling/version mechanism, where + * <p> + * It would also be possible to add some journaling/version mechanism, where * snapshots of the allocation maps are retained for sometime. For a store which * was only added to this would not be an unreasonable overhead and would * support the rolling back of the database weekly or monthly if required. - * + * <p> * The input/output mechanism uses ByteArray Input and Output Streams. - * + * <p> * One difference between the disk realloc and in memory realloc is that the * disk realloc will always return a new address and mark the old address as * ready to be freed. - * + * <p> * The method of storing the allocation headers has been changed from always - * allocting at the end of the file (and moving them on fle extend) to + * allocating at the end of the file (and moving them on fle extend) to * allocation of fixed areas. The meta-allocation data, containing the bitmap * that controls these allocations, is itself stored in the heap, and is now * structured to include both the bit data and the list of meta-storage * addresses. - * + * <p> * Sizing: * 256 allocators would reference approximately 2M objects/allocations. At 1K * per allocator this would require 250K of store. The meta-allocation data * would therefore need a start address plus 32 bytes (or 8 ints) to represent - * the meta-allocation bits. An array of such data referencing sequentialy + * the meta-allocation bits. An array of such data referencing sequentially * allocated storage areas completes the meta-allocation requirements. - * + * <p> * A meta-allocation address can therefore be represented as a single bit offset * from which the block, providing start address, and bit offset can be * directly determined. - * - * The m_metaBits int array used to be fully used as allocaiton bits, but + * <p> + * The m_metaBits int array used to be fully used as allocation bits, but * now stores both the start address plus the 8 ints used to manage that data * block. - * + * <p> * Allocation is reduced to sets of allocator objects which have a start address * and a bitmap of allocated storage maps. - * + * <p> * Searching thousands of allocation blocks to find storage is not efficient, - * but by utilising roving pointers and sorting blocks with free space available + * but by utilizing roving pointers and sorting blocks with free space available * this can be made most efficient. - * + * <p> * In order to provide optimum use of bitmaps, this implementation will NOT use * the BitSet class. - * + * <p> * Using the meta-allocation bits, it is straightforward to load ALL the * allocation headers. A total of (say) 100 allocation headers might provide - * upto 4000 allocations each -> 400 000 objects, while 1000 headers -> 4m + * up to 4000 allocations each -> 400 000 objects, while 1000 headers -> 4m * objects and 2000 -> 8m objects. - * + * <p> * The allocators are split into a set of FixedAllocators and then * BlobAllocation. The FixedAllocators will allocate from 128 to 32K objects, * with a minimum block allocation of 64K, and a minimum bit number per block of * 32. - * + * <p> * Where possible lists and roving pointers will be used to minimise searching * of the potentially large structures. - * + * <p> * Since the memory is allocated on (at least) a 128 byte boundary, there is * some leeway on storing the address. Added to the address is the shift * required to make to the "standard" 128 byte block, e.g. blocksize = 128 << * (addr % 8) - * + * <p> * NB Useful method on RandomAccessFile.setLength(newLength) - * + * <p> * When session data is preserved two things must happen - the allocators must * not reallocate data that has been freed in this session, or more clearly can * only free data that has been allocated in this session. That should be it. - * + * <p> * The ALLOC_SIZES table is the fibonacci sequence. We multiply by 64 bytes to * get actual allocation block sizes. We then allocate bits based on 8K * allocation rounding and 32 bits at a time allocation. Note that 4181 * 64 = * 267,584 and 256K is 262,144 - * + * <p> * All data is checksummed, both allocated/saved data and the allocation blocks. - * + * <p> * BLOB allocation is not handled using chained data buffers but with a blob * header record. This is indicated with a BlobAllocator that provides indexed * offsets to the header record (the address encodes the BlobAllocator and the * offset to the address). The header record stores the number of component * allocations and the address of each. - * + * <p> * This approach makes for much more efficient freeing/re-allocation of Blob * storage, in particular avoiding the need to read in the component blocks * to determine chained blocks for freeing. This is particularly important * for larger stores where a disk cache could be flushed through simply freeing * BLOB allocations. - * + * <h2> * Deferred Free List - * - * The prevous implentation has been amended to associate a single set of + * </h2> + * <p> + * The previous implementation has been amended to associate a single set of * deferredFree blocks with each CommitRecord. The CommitRecordIndex will * then provide access to the CommitRecords to support the deferred freeing * of allocations based on age/earliestTxReleaseTime. + * <p> + * The last release time processed is held with the MetaAllocation data * - * The last release time processed is held with the MetaAllocation data + * @author Martyn Cutcher */ public class RWStore implements IStore { - protected static final Logger log = Logger.getLogger(RWStore.class); + private static final transient Logger log = Logger.getLogger(RWStore.class); + /** * The sizes of the slots managed by a {@link FixedAllocator} are 64 times * the values in this array. * * @todo good to have 4k and 8k boundaries for better efficiency on SSD. - * NB A 1K boundry is % 16, so 4K % 64 + * NB A 1K boundary is % 16, so 4K % 64 * - can still use fibonacci base, but from 4K start * * @todo This array should be configurable and must be written into the @@ -240,8 +241,8 @@ // protected int m_transactionCount; // private boolean m_committing; - boolean m_preserveSession = true; - private boolean m_readOnly; + private boolean m_preserveSession = true; +// private boolean m_readOnly; /** * lists of total alloc blocks. @@ -259,13 +260,13 @@ private final ArrayList<BlobAllocator> m_freeBlobs; // lists of blocks requiring commitment - private final ArrayList m_commitList; + private final ArrayList<Allocator> m_commitList; private WriteBlock m_writes; private final Quorum<?,?> m_quorum; - private RWWriteCacheService m_writeCache; + private final RWWriteCacheService m_writeCache; - int[] m_allocSizes; + private int[] m_allocSizes; /** * This lock is used to exclude readers when the extent of the backing file @@ -310,28 +311,28 @@ /** * The deferredFreeList is simply an array of releaseTime,freeListAddrs * stored at commit. - * + * <p> * Note that when the deferredFreeList is saved, ONLY thefreeListAddrs * are stored, NOT the releaseTime. This is because on any open of * the store, all deferredFrees can be released immediately. This * mechanism may be changed in the future to enable explicit history * retention, but if so a different header structure would be used since * it would not be appropriate to retain a simple header linked to - * thousands if not milions of commit points. - * - * If the current txn list exceeds the MAX_DEFERRED_FREE then it is - * incrementally saved and a new list begun. The master list itself - * serves as a BLOB header when there is more than a single entry with - * the same txReleaseTime. + * thousands if not millions of commit points. */ - private static final int MAX_DEFERRED_FREE = 4094; // fits in 16k block - volatile long m_lastDeferredReleaseTime = 0L;// = 23; // zero is invalid time - final ArrayList<Integer> m_currentTxnFreeList = new ArrayList<Integer>(); - final PSOutputStream m_deferredFreeOut; +// * +// * If the current txn list exceeds the MAX_DEFERRED_FREE then it is +// * incrementally saved and a new list begun. The master list itself +// * serves as a BLOB header when there is more than a single entry with +// * the same txReleaseTime. +// private static final int MAX_DEFERRED_FREE = 4094; // fits in 16k block + private volatile long m_lastDeferredReleaseTime = 0L; +// private final ArrayList<Integer> m_currentTxnFreeList = new ArrayList<Integer>(); + private final PSOutputStream m_deferredFreeOut; private ReopenFileChannel m_reopener = null; - BufferedWrite m_bufferedWrite; + private BufferedWrite m_bufferedWrite; class WriteCacheImpl extends WriteCache.FileChannelScatteredWriteCache { public WriteCacheImpl(final ByteBuffer buf, @@ -350,14 +351,16 @@ final long firstOffsetignored, final Map<Long, RecordMetadata> recordMap, final long nanos) throws InterruptedException, IOException { - Lock readLock = m_extensionLock.readLock(); - readLock.lock(); - try { - return super.writeOnChannel(data, firstOffsetignored, recordMap, nanos); - } finally { - readLock.unlock(); - } - + + final Lock readLock = m_extensionLock.readLock(); + readLock.lock(); + try { + return super.writeOnChannel(data, firstOffsetignored, + recordMap, nanos); + } finally { + readLock.unlock(); + } + } // Added to enable debug of rare problem @@ -368,28 +371,28 @@ }; - private String m_filename; +// private String m_filename; private final FileMetadataView m_fmv; private IRootBlockView m_rb; - volatile private long m_commitCounter; +// volatile private long m_commitCounter; volatile private int m_metaBitsAddr; - /** - * The ALLOC_SIZES must be initialised from either the file - * or the properties associaed with the fileMetadataView - * - * @param fileMetadataView - * @param readOnly - * @param quorum - * @throws InterruptedException - */ + /** + * The ALLOC_SIZES must be initialized from either the file or the + * properties associated with the fileMetadataView + * + * @param fileMetadataView + * @param readOnly + * @param quorum + * @throws InterruptedException + */ - public RWStore(final FileMetadataView fileMetadataView, final boolean readOnly, - final Quorum<?,?> quorum) { + public RWStore(final FileMetadataView fileMetadataView, + final boolean readOnly, final Quorum<?, ?> quorum) { m_metaBitsSize = cDefaultMetaBitsSize; @@ -407,12 +410,13 @@ m_rb = m_fmv.getRootBlock(); - m_filename = m_fd.getAbsolutePath(); +// m_filename = m_fd.getAbsolutePath(); - m_commitList = new ArrayList(); + m_commitList = new ArrayList<Allocator>(); + m_allocs = new ArrayList<Allocator>(); - m_freeBlobs = new ArrayList(); + m_freeBlobs = new ArrayList<BlobAllocator>(); try { m_reopener = new ReopenFileChannel(m_fd, m_raf, "rw"); @@ -426,13 +430,14 @@ m_bufferedWrite = null; } - int buffers = m_fmv.getFileMetadata().writeCacheBufferCount; - log.warn("RWStore using writeCacheService with buffers: " + buffers); + final int buffers = m_fmv.getFileMetadata().writeCacheBufferCount; + if(log.isInfoEnabled()) + log.info("RWStore using writeCacheService with buffers: " + buffers); + try { - m_writeCache = new RWWriteCacheService( - buffers, m_raf - .length(), m_reopener, m_quorum) { + m_writeCache = new RWWriteCacheService(buffers, m_raf.length(), + m_reopener, m_quorum) { public WriteCache newWriteCache(final ByteBuffer buf, final boolean useChecksum, @@ -541,24 +546,23 @@ final long metaAddr = rbv.getMetaStartAddr(); final long rawMetaBitsAddr = rbv.getMetaBitsAddr(); if (metaAddr == 0 || rawMetaBitsAddr == 0) { - log.warn("No meta allocation data included in root block for RWStore"); // possible - // when - // rolling - // back - // to - // empty - // file + /* + * possible when rolling back to empty file. + */ + log.warn("No meta allocation data included in root block for RWStore"); } if (log.isTraceEnabled()) { - int commitRecordAddr = (int) (rbv.getCommitRecordAddr() >> 32); - log.trace("CommitRecord " + rbv.getCommitRecordAddr() + " at physical address: " + physicalAddress(commitRecordAddr)); - } + final int commitRecordAddr = (int) (rbv.getCommitRecordAddr() >> 32); + log.trace("CommitRecord " + rbv.getCommitRecordAddr() + + " at physical address: " + + physicalAddress(commitRecordAddr)); + } final long commitCounter = rbv.getCommitCounter(); - final int metaStartAddr = (int) -(metaAddr >> 32); // void - final int fileSize = (int) -(metaAddr & 0xFFFFFFFF); +// final int metaStartAddr = (int) -(metaAddr >> 32); // void +// final int fileSize = (int) -(metaAddr & 0xFFFFFFFF); if (log.isTraceEnabled()) log.trace("m_allocation: " + nxtalloc + ", m_metaBitsAddr: " @@ -592,7 +596,7 @@ // m_rb = m_fmv.getRootBlock(); assert(m_rb != null); - m_commitCounter = m_rb.getCommitCounter(); +// m_commitCounter = m_rb.getCommitCounter(); final long nxtOffset = m_rb.getNextOffset(); m_nextAllocation = -(int) (nxtOffset >> 32); @@ -607,10 +611,12 @@ m_fileSize = (int) -(metaAddr & 0xFFFFFFFF); long rawmbaddr = m_rb.getMetaBitsAddr(); - int metaBitsStore = (int) (rawmbaddr & 0xFFFF); // take bottom 16 bits ( - // even 1K of metabits - // is more than - // sufficient) + + /* + * Take bottom 16 bits (even 1K of metabits is more than sufficient) + */ + final int metaBitsStore = (int) (rawmbaddr & 0xFFFF); + if (metaBitsStore > 0) { rawmbaddr >>= 16; @@ -623,7 +629,7 @@ m_lastDeferredReleaseTime = strBuf.readLong(); - int allocBlocks = strBuf.readInt(); + final int allocBlocks = strBuf.readInt(); m_allocSizes = new int[allocBlocks]; for (int i = 0; i < allocBlocks; i++) { m_allocSizes[i] = strBuf.readInt(); @@ -643,7 +649,7 @@ m_freeFixed = new ArrayList[numFixed]; for (int i = 0; i < numFixed; i++) { - m_freeFixed[i] = new ArrayList(); + m_freeFixed[i] = new ArrayList<FixedAllocator>(); } checkCoreAllocations(); @@ -669,58 +675,58 @@ + ", " + m_metaBitsAddr); } - /* - * Called when store is opened to make sure any deferred frees are - * cleared. - * - * Stored persistently is only the list of addresses of blocks to be freed, - * the knowledge of the txn release time does not need to be held persistently, - * this is only relevant for transient state while the RWStore is open. - * - * The deferredCount is the number of entries - integer address and integer - * count at each address - */ - private void clearOutstandingDeferrels(final int deferredAddr, final int deferredCount) { - if (deferredAddr != 0) { - assert deferredCount != 0; - final int sze = deferredCount * 8 + 4; // include space for checksum - - if (log.isDebugEnabled()) - log.debug("Clearing Outstanding Deferrals: " + deferredCount); - - byte[] buf = new byte[sze]; - getData(deferredAddr, buf); - - final byte[] blockBuf = new byte[8 * 1024]; // maximum size required - - ByteBuffer in = ByteBuffer.wrap(buf); - for (int i = 0; i < deferredCount; i++) { - int blockAddr = in.getInt(); - int addrCount = in.getInt(); - - // now read in this block and free all addresses referenced - getData(blockAddr, blockBuf, 0, addrCount*4 + 4); - ByteBuffer inblock = ByteBuffer.wrap(blockBuf); - for (int b = 0; b < addrCount; b++) { - final int defAddr = inblock.getInt(); - Allocator alloc = getBlock(defAddr); - if (alloc instanceof BlobAllocator) { - b++; - assert b < addrCount; - alloc.free(defAddr, inblock.getInt()); - } else { - alloc.free(defAddr, 0); // size ignored for FreeAllocators - } - } - // once read then free the block allocation - free(blockAddr, 0); - } - - // lastly free the deferredAddr - free(deferredAddr, 0); - } - - } +// /* +// * Called when store is opened to make sure any deferred frees are +// * cleared. +// * +// * Stored persistently is only the list of addresses of blocks to be freed, +// * the knowledge of the txn release time does not need to be held persistently, +// * this is only relevant for transient state while the RWStore is open. +// * +// * The deferredCount is the number of entries - integer address and integer +// * count at each address +// */ +// private void clearOutstandingDeferrels(final int deferredAddr, final int deferredCount) { +// if (deferredAddr != 0) { +// assert deferredCount != 0; +// final int sze = deferredCount * 8 + 4; // include space for checksum +// +// if (log.isDebugEnabled()) +// log.debug("Clearing Outstanding Deferrals: " + deferredCount); +// +// byte[] buf = new byte[sze]; +// getData(deferredAddr, buf); +// +// final byte[] blockBuf = new byte[8 * 1024]; // maximum size required +// +// ByteBuffer in = ByteBuffer.wrap(buf); +// for (int i = 0; i < deferredCount; i++) { +// int blockAddr = in.getInt(); +// int addrCount = in.getInt(); +// +// // now read in this block and free all addresses referenced +// getData(blockAddr, blockBuf, 0, addrCount*4 + 4); +// ByteBuffer inblock = ByteBuffer.wrap(blockBuf); +// for (int b = 0; b < addrCount; b++) { +// final int defAddr = inblock.getInt(); +// Allocator alloc = getBlock(defAddr); +// if (alloc instanceof BlobAllocator) { +// b++; +// assert b < addrCount; +// alloc.free(defAddr, inblock.getInt()); +// } else { +// alloc.free(defAddr, 0); // size ignored for FreeAllocators +// } +// } +// // once read then free the block allocation +// free(blockAddr, 0); +// } +// +// // lastly free the deferredAddr +// free(deferredAddr, 0); +// } +// +// } /********************************************************************* * make sure resource is closed! @@ -733,8 +739,9 @@ assert m_allocs.size() == 0; - System.out.println("readAllocationBlocks, m_metaBits.length: " - + m_metaBits.length); + if (log.isInfoEnabled()) + log.info("readAllocationBlocks, m_metaBits.length: " + + m_metaBits.length); /** * Allocators are sorted in StartAddress order (which MUST be the order @@ -744,15 +751,15 @@ * address (must be two version of same Allocator). * * Meta-Allocations stored as {int address; int[8] bits}, so each block - * holds 8*32=256 allocation slots of 1K totalling 256K. + * holds 8*32=256 allocation slots of 1K totaling 256K. */ for (int b = 0; b < m_metaBits.length; b += 9) { - long blockStart = convertAddr(m_metaBits[b]); - int startBit = (b * 32) + 32; - int endBit = startBit + (8*32); + final long blockStart = convertAddr(m_metaBits[b]); + final int startBit = (b * 32) + 32; + final int endBit = startBit + (8*32); for (int i = startBit; i < endBit; i++) { if (tstBit(m_metaBits, i)) { - long addr = blockStart + ((i-startBit) * ALLOC_BLOCK_SIZE); + final long addr = blockStart + ((i-startBit) * ALLOC_BLOCK_SIZE); final byte buf[] = new byte[ALLOC_BLOCK_SIZE]; @@ -761,8 +768,8 @@ final DataInputStream strBuf = new DataInputStream(new ByteArrayInputStream(buf)); final int allocSize = strBuf.readInt(); // if Blob < 0 - Allocator allocator = null; - ArrayList freeList = null; + final Allocator allocator; + final ArrayList<? extends Allocator> freeList; if (allocSize > 0) { int index = 0; int fixedSize = m_minFixedAlloc; @@ -811,16 +818,20 @@ * ContextAllocation is released, its allocators will be added to the * global free lists. * - * @param block - the index of the Fixed size alloction + * @param block - the index of the Fixed size allocation * @return the FixedAllocator */ - FixedAllocator establishFreeFixedAllocator(int block) { - ArrayList<FixedAllocator> list = m_freeFixed[block]; + private FixedAllocator establishFreeFixedAllocator(final int block) { + + final ArrayList<FixedAllocator> list = m_freeFixed[block]; if (list.size() == 0) { - final int allocSize = 64 * m_allocSizes[block]; + + final int allocSize = 64 * m_allocSizes[block]; - FixedAllocator allocator = new FixedAllocator(this, allocSize, m_writeCache); + final FixedAllocator allocator = new FixedAllocator(this, + allocSize, m_writeCache); + allocator.setIndex(m_allocs.size()); m_allocs.add(allocator); @@ -855,7 +866,7 @@ // } public long getMaxFileSize() { - long maxSize = m_maxFileSize; + final long maxSize = m_maxFileSize; return maxSize << 8; } @@ -914,12 +925,14 @@ * If it is a BlobAllocation, then the BlobAllocation address points to the address of the BlobHeader * record. */ - public void getData(long addr, byte buf[]) { + public void getData(final long addr, final byte buf[]) { getData(addr, buf, 0, buf.length); } - public void getData(long addr, byte buf[], int offset, int length) { - if (addr == 0) { + public void getData(final long addr, final byte buf[], final int offset, + final int length) { + + if (addr == 0) { return; } @@ -931,19 +944,24 @@ // length includes space for the checksum if (length > m_maxFixedAlloc) { try { - int alloc = m_maxFixedAlloc-4; - int nblocks = (alloc - 1 + (length-4))/alloc; - if (nblocks < 0) throw new IllegalStateException("Allocation error, m_maxFixedAlloc: "+ m_maxFixedAlloc); - - byte[] hdrbuf = new byte[4 * (nblocks + 1) + 4]; // plus 4 bytes for checksum - BlobAllocator ba = (BlobAllocator) getBlock((int) addr); + final int alloc = m_maxFixedAlloc-4; + final int nblocks = (alloc - 1 + (length-4))/alloc; + if (nblocks < 0) + throw new IllegalStateException( + "Allocation error, m_maxFixedAlloc: " + + m_maxFixedAlloc); + + final byte[] hdrbuf = new byte[4 * (nblocks + 1) + 4]; // plus 4 bytes for checksum + final BlobAllocator ba = (BlobAllocator) getBlock((int) addr); getData(ba.getBlobHdrAddress(getOffset((int) addr)), hdrbuf); // read in header - DataInputStream hdrstr = new DataInputStream(new ByteArrayInputStream(hdrbuf)); - int rhdrs = hdrstr.readInt(); - if (rhdrs != nblocks) { - throw new IllegalStateException("Incompatible BLOB header record, expected: " + nblocks + ", got: " + rhdrs); - } - int[] blobHdr = new int[nblocks]; + final DataInputStream hdrstr = new DataInputStream(new ByteArrayInputStream(hdrbuf)); + final int rhdrs = hdrstr.readInt(); + if (rhdrs != nblocks) { + throw new IllegalStateException( + "Incompatible BLOB header record, expected: " + + nblocks + ", got: " + rhdrs); + } + final int[] blobHdr = new int[nblocks]; for (int i = 0; i < nblocks; i++) { blobHdr[i] = hdrstr.readInt(); } @@ -968,7 +986,7 @@ } try { - long paddr = physicalAddress((int) addr); + final long paddr = physicalAddress((int) addr); if (paddr == 0) { assertAllocators(); @@ -984,19 +1002,25 @@ * value, so the cached data is 4 bytes less than the * buffer size. */ - ByteBuffer bbuf = null; + final ByteBuffer bbuf; try { bbuf = m_writeCache.read(paddr); } catch (Throwable t) { - throw new IllegalStateException("Error reading from WriteCache addr: " + paddr + " length: " + (length-4) + ", writeCacheDebug: " + m_writeCache.addrDebugInfo(paddr), t); + throw new IllegalStateException( + "Error reading from WriteCache addr: " + paddr + + " length: " + (length - 4) + + ", writeCacheDebug: " + + m_writeCache.addrDebugInfo(paddr), t); } if (bbuf != null) { - byte[] in = bbuf.array(); // reads in with checksum - no need to check if in cache + final byte[] in = bbuf.array(); // reads in with checksum - no need to check if in cache if (in.length != length-4) { assertAllocators(); - - throw new IllegalStateException("Incompatible buffer size for addr: " + paddr + ", " + in.length - + " != " + (length-4) + " writeCacheDebug: " + m_writeCache.addrDebugInfo(paddr)); + throw new IllegalStateException( + "Incompatible buffer size for addr: " + paddr + + ", " + in.length + " != " + + (length - 4) + " writeCacheDebug: " + + m_writeCache.addrDebugInfo(paddr)); } for (int i = 0; i < length-4; i++) { buf[offset+i] = in[i]; @@ -1004,21 +1028,23 @@ m_cacheReads++; } else { // If checksum is required then the buffer should be sized to include checksum in final 4 bytes - ByteBuffer bb = ByteBuffer.wrap(buf, offset, length); + final ByteBuffer bb = ByteBuffer.wrap(buf, offset, length); FileChannelUtility.readAll(m_reopener, bb, paddr); - int chk = ChecksumUtility.getCHK().checksum(buf, offset, length-4); // read checksum - int tstchk = bb.getInt(offset + length-4); + final int chk = ChecksumUtility.getCHK().checksum(buf, offset, length-4); // read checksum + final int tstchk = bb.getInt(offset + length-4); if (chk != tstchk) { assertAllocators(); - String cacheDebugInfo = m_writeCache.addrDebugInfo(paddr); + final String cacheDebugInfo = m_writeCache.addrDebugInfo(paddr); log.warn("Invalid data checksum for addr: " + paddr + ", chk: " + chk + ", tstchk: " + tstchk + ", length: " + length + ", first bytes: " + toHexString(buf, 32) + ", successful reads: " + m_diskReads + ", at last extend: " + m_readsAtExtend + ", cacheReads: " + m_cacheReads + ", writeCacheDebug: " + cacheDebugInfo); - throw new IllegalStateException("Invalid data checksum from address: " + paddr + ", size: " + (length-4)); + throw new IllegalStateException( + "Invalid data checksum from address: " + paddr + + ", size: " + (length - 4)); } m_diskReads++; @@ -1042,7 +1068,7 @@ } } - static final char[] HEX_CHAR_TABLE = { + static private final char[] HEX_CHAR_TABLE = { '0', '1','2','3', '4','5','6','7', '8','9','a','b', @@ -1050,11 +1076,11 @@ }; // utility to display byte array of maximum i bytes as hexString - private String toHexString(byte[] buf, int n) { + static private String toHexString(final byte[] buf, int n) { n = n < buf.length ? n : buf.length; - StringBuffer out = new StringBuffer(); + final StringBuffer out = new StringBuffer(); for (int i = 0; i < n; i++) { - int v = buf[i] & 0xFF; + final int v = buf[i] & 0xFF; out.append(HEX_CHAR_TABLE[v >>> 4]); out.append(HEX_CHAR_TABLE[v &0xF]); } @@ -1094,7 +1120,7 @@ * this supports the core functionality of a WormStore, other stores should * return zero, indicating no previous versions available **/ - public long getPreviousAddress(long laddr) { + public long getPreviousAddress(final long laddr) { return 0; } @@ -1135,7 +1161,7 @@ * is NOT owned, BUT there are active AllocationContexts, in this * situation, the free must ALWAYS be deferred. */ - boolean alwaysDefer = context == null && m_contexts.size() > 0; + final boolean alwaysDefer = context == null && m_contexts.size() > 0; if (alwaysDefer) if (log.isDebugEnabled()) log.debug("Should defer " + physicalAddress(addr)); @@ -1150,7 +1176,7 @@ } - private long immediateFreeCount = 0; +// private long immediateFreeCount = 0; private void immediateFree(final int addr, final int sze) { switch (addr) { @@ -1215,10 +1241,10 @@ * by the finer granularity of the AllocBlocks within a FixedAllocator. */ - private volatile long m_maxAllocation = 0; +// private volatile long m_maxAllocation = 0; private volatile long m_spareAllocation = 0; - public int alloc(final int size, IAllocationContext context) { + public int alloc(final int size, final IAllocationContext context) { if (size > m_maxFixedAlloc) { throw new IllegalArgumentException("Allocation size to big: " + size); } @@ -1226,8 +1252,7 @@ m_allocationLock.lock(); try { try { - ArrayList list; - Allocator allocator = null; + final Allocator allocator; final int i = fixedAllocatorIndex(size); if (context != null) { allocator = establishContextAllocation(context).getFreeFixed(i); @@ -1235,7 +1260,7 @@ final int block = 64 * m_allocSizes[i]; m_spareAllocation += (block - size); // Isn't adjusted by frees! - list = m_freeFixed[i]; + final ArrayList<FixedAllocator> list = m_freeFixed[i]; if (list.size() == 0) { allocator = new FixedAllocator(this, block, m_writeCache); @@ -1250,9 +1275,9 @@ // Verify free list only has allocators with free bits if (log.isDebugEnabled()){ int tsti = 0; - Iterator<Allocator> allocs = list.iterator(); + final Iterator<FixedAllocator> allocs = list.iterator(); while (allocs.hasNext()) { - Allocator tstAlloc = allocs.next(); + final Allocator tstAlloc = allocs.next(); if (!tstAlloc.hasFree()) { throw new IllegalStateException("Free list contains full allocator, " + tsti + " of " + list.size()); } @@ -1272,10 +1297,11 @@ m_recentAlloc = true; - long pa = physicalAddress(addr); - if (pa == 0L) { - throw new IllegalStateException("No physical address found for " + addr); - } + final long pa = physicalAddress(addr); + if (pa == 0L) { + throw new IllegalStateException( + "No physical address found for " + addr); + } m_allocations++; m_nativeAllocBytes += size; @@ -1291,7 +1317,7 @@ } } - int fixedAllocatorIndex(int size) { + int fixedAllocatorIndex(final int size) { int i = 0; int cmp = m_minFixedAlloc; @@ -1530,12 +1556,24 @@ * simply reset the metaBitsAddr * @throws IOException */ - protected void writeFileSpec() throws IOException { - m_rb = m_fmv.newRootBlockView(!m_rb.isRootBlock0(), m_rb.getOffsetBits(), getNextOffset(), m_rb - .getFirstCommitTime(), m_rb.getLastCommitTime(), m_rb.getCommitCounter(), m_rb.getCommitRecordAddr(), - m_rb.getCommitRecordIndexAddr(), getMetaStartAddr(), getMetaBitsAddr(), m_rb.getLastCommitTime()); - - m_fmv.getFileMetadata().writeRootBlock(m_rb, ForceEnum.Force); + protected void writeFileSpec() throws IOException { + + m_rb = m_fmv.newRootBlockView(// + !m_rb.isRootBlock0(), // + m_rb.getOffsetBits(), // + getNextOffset(), // + m_rb.getFirstCommitTime(),// + m_rb.getLastCommitTime(), // + m_rb.getCommitCounter(), // + m_rb.getCommitRecordAddr(),// + m_rb.getCommitRecordIndexAddr(), // + getMetaStartAddr(),// + getMetaBitsAddr(), // + m_rb.getLastCommitTime()// + ); + + m_fmv.getFileMetadata().writeRootBlock(m_rb, ForceEnum.Force); + } // float m_vers = 0.0f; @@ -1582,8 +1620,8 @@ checkDeferredFrees(true, journal); // free now if possible // Allocate storage for metaBits - long oldMetaBits = m_metaBitsAddr; - int oldMetaBitsSize = (m_metaBits.length + m_allocSizes.length + 1) * 4; + final long oldMetaBits = m_metaBitsAddr; + final int oldMetaBitsSize = (m_metaBits.length + m_allocSizes.length + 1) * 4; m_metaBitsAddr = alloc(getRequiredMetaBitsStorage(), null); // DEBUG SANITY CHECK! @@ -1596,18 +1634,18 @@ immediateFree((int) oldMetaBits, oldMetaBitsSize); // save allocation headers - Iterator iter = m_commitList.iterator(); + final Iterator<Allocator> iter = m_commitList.iterator(); while (iter.hasNext()) { - final Allocator allocator = (Allocator) iter.next(); + final Allocator allocator = iter.next(); final int old = allocator.getDiskAddr(); metaFree(old); final int naddr = metaAlloc(); allocator.setDiskAddr(naddr); - if (log.isTraceEnabled()) - log.trace("Update allocator " + allocator.getIndex() + ", old addr: " + old + ", new addr: " - + naddr); + if (log.isTraceEnabled()) + log.trace("Update allocator " + allocator.getIndex() + + ", old addr: " + old + ", new addr: " + naddr); try { m_writeCache.write(metaBit2Addr(naddr), ByteBuffer.wrap(allocator.write()), 0, false); // do not use checksum @@ -1647,16 +1685,21 @@ checkCoreAllocations(); - if (log.isTraceEnabled()) - log.trace("commitChanges for: " + m_nextAllocation + ", " + m_metaBitsAddr + ", active contexts: " + m_contexts.size()); - } + if (log.isTraceEnabled()) + log.trace("commitChanges for: " + m_nextAllocation + ", " + + m_metaBitsAddr + ", active contexts: " + + m_contexts.size()); + } - /** - * Called prior to commit, so check whether storage can be freed and then - * whether the deferredheader needs to be saved. - * <p> - * Note: The caller MUST be holding the {@link #m_allocationLock}. - */ + /** + * Called prior to commit, so check whether storage can be freed and then + * whether the deferredheader needs to be saved. + * <p> + * Note: The caller MUST be holding the {@link #m_allocationLock}. + * <p> + * Note: This method is package private in order to expose it to the unit + * tests.... [truncated message content] |
From: <tho...@us...> - 2010-11-03 14:33:59
|
Revision: 3877 http://bigdata.svn.sourceforge.net/bigdata/?rev=3877&view=rev Author: thompsonbry Date: 2010-11-03 14:33:52 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Working through some issues with interrupts, reopen, and shadow journals with Martyn. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 13:17:41 UTC (rev 3876) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 14:33:52 UTC (rev 3877) @@ -269,27 +269,39 @@ checkReopen(); - if (data == null) { + if (data == null) throw new IllegalArgumentException(); - } - + + if (data.hasArray() && data.arrayOffset() != 0) { + /* + * FIXME [data] is not always backed by an array, the array may not + * be visible (read-only), the array offset may not be zero, etc. + * Try to drive the ByteBuffer into the RWStore.alloc() method + * instead. + * + * See https://sourceforge.net/apps/trac/bigdata/ticket/151 + */ + throw new AssertionError(); + } + final int nbytes = data.remaining(); - if (nbytes == 0) { + if (nbytes == 0) throw new IllegalArgumentException(); - } - try { /* FIXME [data] is not always backed by an array, the array may not be visible (read-only), the array offset may not be zero, etc. Try to drive the ByteBuffer into the RWStore.alloc() method instead. */ - if(data.hasArray()&&data.arrayOffset()!=0)throw new AssertionError(); - final long rwaddr = m_store.alloc(data.array(), nbytes, context); - data.position(nbytes); // update position to end of buffer + try { + + final long rwaddr = m_store.alloc(data.array(), nbytes, context); + + data.position(nbytes); // update position to end of buffer final long retaddr = encodeAddr(rwaddr, nbytes); return retaddr; - } catch (RuntimeException re) { + + } catch (RuntimeException re) { - re.printStackTrace(); + log.error(re,re);//re.printStackTrace(); m_needsReopen = true; @@ -521,7 +533,7 @@ m_fileMetadata.raf.close(); m_fileMetadata.raf = null; } catch (IOException e) { - e.printStackTrace(); + log.error(e,e);//e.printStackTrace(); } } @@ -641,7 +653,7 @@ m_needsReopen = false; m_open = true; } catch (Throwable t) { - t.printStackTrace(); + log.error(t,t); throw new RuntimeException(t); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java 2010-11-03 13:17:41 UTC (rev 3876) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java 2010-11-03 14:33:52 UTC (rev 3877) @@ -213,23 +213,23 @@ **/ public int bufferChainOffset(); - public void absoluteWriteLong(long addr, int threshold, long value); - - /*************************************************************************************** - * Needed by PSOutputStream for BLOB buffer chaining. - **/ - public void absoluteWriteInt(int addr, int offset, int value); +// public void absoluteWriteLong(long addr, int threshold, long value); +// +// /*************************************************************************************** +// * Needed by PSOutputStream for BLOB buffer chaining. +// **/ +// public void absoluteWriteInt(int addr, int offset, int value); +// +// /*************************************************************************************** +// * Needed to free Blob chains. +// **/ +// public int absoluteReadInt(int addr, int offset); +// +// /*************************************************************************************** +// * Needed to free Blob chains. +// **/ +// public int absoluteReadLong(long addr, int offset); - /*************************************************************************************** - * Needed to free Blob chains. - **/ - public int absoluteReadInt(int addr, int offset); - - /*************************************************************************************** - * Needed to free Blob chains. - **/ - public int absoluteReadLong(long addr, int offset); - // /*************************************************************************************** // * copies the store to a new file, this is not necessarily a byte for byte copy // * since the store could write only consolidated data - particulalry relevant for the @@ -264,7 +264,7 @@ **/ public File getStoreFile(); - public void absoluteWriteAddress(long addr, int threshold, long addr2); +// public void absoluteWriteAddress(long addr, int threshold, long addr2); public int getAddressSize(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 13:17:41 UTC (rev 3876) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 14:33:52 UTC (rev 3877) @@ -235,7 +235,7 @@ // RWStore Data // /////////////////////////////////////////////////////////////////////////////////////// - private File m_fd; + private final File m_fd; private RandomAccessFile m_raf; // protected FileMetadata m_metadata; // protected int m_transactionCount; @@ -967,7 +967,7 @@ return; } catch (IOException e) { - e.printStackTrace(); + log.error(e,e); throw new IllegalStateException("Unable to restore Blob allocation", e); } @@ -1435,11 +1435,10 @@ // } // } - // -------------------------------------------------------------------------------------------- - // reset - // - // Similar to rollbackTransaction but will force a re-initialization if transactions are not being - // used - update w/o commit protocol. + /** + * Toss away all buffered writes and then reload from the current root + * block. + */ public void reset() { if (log.isInfoEnabled()) { log.info("RWStore Reset"); @@ -1459,13 +1458,13 @@ try { m_writeCache.reset(); } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + throw new RuntimeException(e); } initfromRootBlock(); - m_writeCache.setExtent(convertAddr(m_fileSize)); // notify of current file length. + // notify of current file length. + m_writeCache.setExtent(convertAddr(m_fileSize)); } catch (Exception e) { throw new IllegalStateException("Unable reset the store", e); } finally { @@ -1607,67 +1606,67 @@ m_allocationLock.lock(); try { - - checkDeferredFrees(true, journal); // free now if possible + + checkDeferredFrees(true, journal); // free now if possible - // Allocate storage for metaBits - final long oldMetaBits = m_metaBitsAddr; - final int oldMetaBitsSize = (m_metaBits.length + m_allocSizes.length + 1) * 4; - m_metaBitsAddr = alloc(getRequiredMetaBitsStorage(), null); + // Allocate storage for metaBits + final long oldMetaBits = m_metaBitsAddr; + final int oldMetaBitsSize = (m_metaBits.length + m_allocSizes.length + 1) * 4; + m_metaBitsAddr = alloc(getRequiredMetaBitsStorage(), null); - // DEBUG SANITY CHECK! - if (physicalAddress(m_metaBitsAddr) == 0) { - throw new IllegalStateException("Returned MetaBits Address not valid!"); - } + // DEBUG SANITY CHECK! + if (physicalAddress(m_metaBitsAddr) == 0) { + throw new IllegalStateException("Returned MetaBits Address not valid!"); + } - // Call immediateFree - no need to defer freeof metaBits, this - // has to stop somewhere! - immediateFree((int) oldMetaBits, oldMetaBitsSize); + // Call immediateFree - no need to defer freeof metaBits, this + // has to stop somewhere! + immediateFree((int) oldMetaBits, oldMetaBitsSize); - // save allocation headers - final Iterator<Allocator> iter = m_commitList.iterator(); - while (iter.hasNext()) { - final Allocator allocator = iter.next(); - final int old = allocator.getDiskAddr(); - metaFree(old); - - final int naddr = metaAlloc(); - allocator.setDiskAddr(naddr); - - if (log.isTraceEnabled()) - log.trace("Update allocator " + allocator.getIndex() - + ", old addr: " + old + ", new addr: " + naddr); + // save allocation headers + final Iterator<Allocator> iter = m_commitList.iterator(); + while (iter.hasNext()) { + final Allocator allocator = iter.next(); + final int old = allocator.getDiskAddr(); + metaFree(old); + + final int naddr = metaAlloc(); + allocator.setDiskAddr(naddr); + + if (log.isTraceEnabled()) + log.trace("Update allocator " + allocator.getIndex() + + ", old addr: " + old + ", new addr: " + naddr); - try { - // do not use checksum - m_writeCache.write(metaBit2Addr(naddr), ByteBuffer - .wrap(allocator.write()), 0, false); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - m_commitList.clear(); - - writeMetaBits(); - try { - m_writeCache.flush(true); + // do not use checksum + m_writeCache.write(metaBit2Addr(naddr), ByteBuffer + .wrap(allocator.write()), 0, false); } catch (InterruptedException e) { - e.printStackTrace(); throw new RuntimeException(e); } + } + m_commitList.clear(); - // Should not write rootBlock, this is responsibility of client - // to provide control - // writeFileSpec(); + writeMetaBits(); - m_metaTransientBits = (int[]) m_metaBits.clone(); + try { + m_writeCache.flush(true); + } catch (InterruptedException e) { + log.error(e, e); + throw new RuntimeException(e); + } + // Should not write rootBlock, this is responsibility of client + // to provide control + // writeFileSpec(); + + m_metaTransientBits = (int[]) m_metaBits.clone(); + // if (m_commitCallback != null) { // m_commitCallback.commitComplete(); // } - m_raf.getChannel().force(false); // TODO, check if required! + m_raf.getChannel().force(false); // TODO, check if required! } catch (IOException e) { throw new StorageTerminalError("Unable to commit transaction", e); } finally { @@ -2385,35 +2384,35 @@ // } // } - /*************************************************************************************** - * Needed by PSOutputStream for BLOB buffer chaining. - **/ - public void absoluteWriteInt(final int addr, final int offset, final int value) { - try { - // must check write cache!!, or the write may be overwritten - just - // flush for now - m_writes.flush(); +// /*************************************************************************************** +// * Needed by PSOutputStream for BLOB buffer chaining. +// **/ +// public void absoluteWriteInt(final int addr, final int offset, final int value) { +// try { +// // must check write cache!!, or the write may be overwritten - just +// // flush for now +// m_writes.flush(); +// +// m_raf.seek(physicalAddress(addr) + offset); +// m_raf.writeInt(value); +// } catch (IOException e) { +// throw new StorageTerminalError("Unable to write integer", e); +// } +// } - m_raf.seek(physicalAddress(addr) + offset); - m_raf.writeInt(value); - } catch (IOException e) { - throw new StorageTerminalError("Unable to write integer", e); - } - } +// /*************************************************************************************** +// * Needed to free Blob chains. +// **/ +// public int absoluteReadInt(final int addr, final int offset) { +// try { +// m_raf.seek(physicalAddress(addr) + offset); +// return m_raf.readInt(); +// } catch (IOException e) { +// throw new StorageTerminalError("Unable to write integer", e); +// } +// } /*************************************************************************************** - * Needed to free Blob chains. - **/ - public int absoluteReadInt(final int addr, final int offset) { - try { - m_raf.seek(physicalAddress(addr) + offset); - return m_raf.readInt(); - } catch (IOException e) { - throw new StorageTerminalError("Unable to write integer", e); - } - } - - /*************************************************************************************** * Needed by PSOutputStream for BLOB buffer chaining. **/ public int bufferChainOffset() { @@ -2429,30 +2428,29 @@ return false; } - public int absoluteReadLong(long addr, int offset) { - throw new UnsupportedOperationException(); - } +// public int absoluteReadLong(long addr, int offset) { +// throw new UnsupportedOperationException(); +// } +// +// public void absoluteWriteLong(long addr, int threshold, long value) { +// throw new UnsupportedOperationException(); +// } - public void absoluteWriteLong(long addr, int threshold, long value) { - throw new UnsupportedOperationException(); - } +// public void absoluteWriteAddress(long addr, int threshold, long addr2) { +// absoluteWriteInt((int) addr, threshold, (int) addr2); +// } - public void absoluteWriteAddress(long addr, int threshold, long addr2) { - absoluteWriteInt((int) addr, threshold, (int) addr2); - } - public int getAddressSize() { return 4; } - // DiskStrategy Support - public RandomAccessFile getRandomAccessFile() { - return m_raf; - } +// public RandomAccessFile getRandomAccessFile() { +// return m_raf; +// } - public FileChannel getChannel() { - return m_raf.getChannel(); - } +// public FileChannel getChannel() { +// return m_raf.getChannel(); +// } public boolean requiresCommit() { return m_recentAlloc; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java 2010-11-03 13:17:41 UTC (rev 3876) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/AbstractInterruptsTestCase.java 2010-11-03 14:33:52 UTC (rev 3877) @@ -145,14 +145,14 @@ * "get()" this task since that will block and the 'interrupt' task * will not run. */ + final long maxWaitMillis = 5*1000; journal.submit(new AbstractTask(journal,ITx.UNISOLATED,new String[]{}){ protected Object doTask() throws Exception { - // sleep for 10 seconds. + // sleep for a bit. + Thread.sleep(maxWaitMillis/*millis*/); - Thread.sleep(10*1000); - throw new AssertionError("Not expecting to wake up."); }}); @@ -182,12 +182,19 @@ log.warn("Waiting for the write service to commit or abort"); + final long begin = System.currentTimeMillis(); while (journal.getConcurrencyManager().writeService.getAbortCount() == 0 && journal.getConcurrencyManager().writeService .getGroupCommitCount() == 0) { - Thread.sleep(10); + final long elapsed = System.currentTimeMillis() - begin; + + if (elapsed > maxWaitMillis) { + fail("Did not abort/commit after " + elapsed + "ms"); + } + Thread.sleep(10/*ms*/); + } // did abort. @@ -241,7 +248,10 @@ final BTree ndx = (BTree) getIndex(getOnlyResource()); // write on the index. - ndx.insert(new byte[]{},new byte[]{}); +// final byte[] val = new byte[Bytes.kilobyte32]; +// for (int i = 0; i < (Bytes.megabyte32 / Bytes.kilobyte32) + 1; i++) +// ndx.insert(new byte[i], val); + ndx.insert(new byte[0], new byte[0]); /* * Now provoke a ClosedByInterruptException. @@ -260,10 +270,10 @@ } catch(Exception ex) { - assertTrue(isInnerCause(ex, ClosedByInterruptException.class)); +// log.warn("Provoked expected root cause exception: " + ex, ex); +// +// assertTrue(isInnerCause(ex, ClosedByInterruptException.class)); - log.info("Provoked expected root cause exception: " + ex); - throw ex; } catch(Throwable t) { @@ -283,7 +293,7 @@ * {@link FileChannel} after a {@link ClosedByInterruptException}. * <p> * The test uses the {@link IRawStore} API. It writes an initial record on - * the store and commits. It then interrupts the main thread and then + * the store. It then interrupts the main thread and then * performs another low level write on the store. The store is then forced * to disk to ensure that a {@link ClosedByInterruptException} is triggered * (during an IO), (alternatively, an {@link InterruptedException} can be @@ -308,14 +318,14 @@ final long addr1 = store.write(rec1); - if (store instanceof IAtomicStore) { - - assertNotSame(0L, ((IAtomicStore)store).commit()); - - } else if (store instanceof RWStrategy) { - RWStrategy rws = (RWStrategy)store; - rws.commit(null); - } +// if (store instanceof IAtomicStore) { +// +// assertNotSame(0L, ((IAtomicStore)store).commit()); +// +// } else if (store instanceof RWStrategy) { +// RWStrategy rws = (RWStrategy)store; +// rws.commit(null); +// } try { @@ -325,7 +335,7 @@ store.force(true); - fail("Expecting: " + ClosedByInterruptException.class); + fail("Expecting to be interrupted."); } catch (Throwable t) { Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java 2010-11-03 13:17:41 UTC (rev 3876) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java 2010-11-03 14:33:52 UTC (rev 3877) @@ -240,7 +240,8 @@ properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - return new Journal(properties); + return new Journal(properties).getBufferStrategy(); +// return new Journal(properties); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 13:17:41 UTC (rev 3876) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 14:33:52 UTC (rev 3877) @@ -1149,8 +1149,8 @@ properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - // return new Journal(properties).getBufferStrategy(); - return new Journal(properties); + return new Journal(properties).getBufferStrategy(); +// return new Journal(properties); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-03 17:09:18
|
Revision: 3882 http://bigdata.svn.sourceforge.net/bigdata/?rev=3882&view=rev Author: thompsonbry Date: 2010-11-03 17:09:11 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Sync to martyn. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DeleteBlockCommitter.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockView.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DeleteBlockCommitter.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DeleteBlockCommitter.java 2010-11-03 16:20:20 UTC (rev 3881) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DeleteBlockCommitter.java 2010-11-03 17:09:11 UTC (rev 3882) @@ -33,13 +33,18 @@ */ public class DeleteBlockCommitter implements ICommitter { - private RWStrategy m_strategy; + private final RWStrategy m_strategy; - public DeleteBlockCommitter(RWStrategy strategy) { - m_strategy = strategy; + public DeleteBlockCommitter(final RWStrategy strategy) { + + m_strategy = strategy; + } - public long handleCommit(long commitTime) { - return m_strategy.saveDeleteBlocks(); + + public long handleCommit(final long commitTime) { + + return m_strategy.getRWStore().saveDeferrals(); + } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-11-03 16:20:20 UTC (rev 3881) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-11-03 17:09:11 UTC (rev 3882) @@ -187,12 +187,12 @@ /** * Offset of the first root block in the file. */ - static final int OFFSET_ROOT_BLOCK0 = SIZE_MAGIC + SIZE_VERSION; + public static final int OFFSET_ROOT_BLOCK0 = SIZE_MAGIC + SIZE_VERSION; /** * Offset of the second root block in the file. */ - static final int OFFSET_ROOT_BLOCK1 = SIZE_MAGIC + SIZE_VERSION + (SIZEOF_ROOT_BLOCK * 1); + public static final int OFFSET_ROOT_BLOCK1 = SIZE_MAGIC + SIZE_VERSION + (SIZEOF_ROOT_BLOCK * 1); /** * The size of the journal header, including MAGIC, version, and both root @@ -1225,32 +1225,32 @@ } - public void writeRootBlock(final IRootBlockView rootBlock, - final ForceEnum forceOnCommit) throws IOException { +// public void writeRootBlock(final IRootBlockView rootBlock, +// final ForceEnum forceOnCommit) throws IOException { +// +// if (rootBlock == null) +// throw new IllegalArgumentException(); +// +// final ByteBuffer data = rootBlock.asReadOnlyBuffer(); +// +// final long pos = rootBlock.isRootBlock0() ? OFFSET_ROOT_BLOCK0 : OFFSET_ROOT_BLOCK1; +// +// final FileChannel channel = raf.getChannel(); +// +// channel.write(data, pos); +// +// if (forceOnCommit != ForceEnum.No) { +// +// channel.force(forceOnCommit == ForceEnum.ForceMetadata); +// +// } +// +// if (log.isTraceEnabled()) +// log.trace("Writing ROOTBLOCK with commitCounter: " + rootBlock.getCommitCounter() +// + ", commitRecordIndexAddr: " + rootBlock.getCommitRecordIndexAddr() +// + ", commitRecordAddr: " + rootBlock.getCommitRecordAddr()); +// } - if (rootBlock == null) - throw new IllegalArgumentException(); - - final ByteBuffer data = rootBlock.asReadOnlyBuffer(); - - final long pos = rootBlock.isRootBlock0() ? OFFSET_ROOT_BLOCK0 : OFFSET_ROOT_BLOCK1; - - final FileChannel channel = raf.getChannel(); - - channel.write(data, pos); - - if (forceOnCommit != ForceEnum.No) { - - channel.force(forceOnCommit == ForceEnum.ForceMetadata); - - } - - if (log.isTraceEnabled()) - log.trace("Writing ROOTBLOCK with commitCounter: " + rootBlock.getCommitCounter() - + ", commitRecordIndexAddr: " + rootBlock.getCommitRecordIndexAddr() - + ", commitRecordAddr: " + rootBlock.getCommitRecordAddr()); - } - /** * Prepare a journal file for use by an {@link IBufferStrategy}. The file * will be created if necessary as permitted and instructed by the specified Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 16:20:20 UTC (rev 3881) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 17:09:11 UTC (rev 3882) @@ -28,7 +28,6 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; -import java.nio.channels.ClosedByInterruptException; import java.util.UUID; import java.util.concurrent.locks.ReentrantLock; @@ -71,7 +70,7 @@ final private FileMetadata m_fileMetadata; - final private Quorum<?,?> m_environment; +// final private Quorum<?,?> m_environment; /** * The backing store impl. @@ -85,8 +84,8 @@ private volatile boolean m_open = false; private volatile IRootBlockView m_rb; - private volatile IRootBlockView m_rb0; - private volatile IRootBlockView m_rb1; +// private volatile IRootBlockView m_rb0; +// private volatile IRootBlockView m_rb1; /** * @todo The use of this lock is suspicious. It is only used by @@ -96,14 +95,6 @@ */ private final ReentrantLock m_commitLock = new ReentrantLock(); -// /** -// * Access to the transaction manager of any owning Journal, needed by -// * RWStrategy to manager deleted data. -// */ -// private AbstractLocalTransactionManager localTransactionManager = null; - -// CounterSet m_counters = new CounterSet(); - /** * It is important to ensure that the RWStrategy keeps a check on the physical root blocks and uses * to manage re-opening of the store. @@ -114,46 +105,46 @@ m_fileMetadata = fileMetadata; - m_environment = quorum; +// m_environment = quorum; m_rb = fileMetadata.rootBlock; - m_store = new RWStore(m_fmv, false, quorum); // not read-only for now + m_store = new RWStore(m_fmv, false/*readOnly*/, quorum); // not read-only for now m_open = true; m_rb = getRootBlock(); // ensure values correct from create/reopen - m_rb0 = copyRootBlock(true); - m_rb1 = copyRootBlock(false); +// m_rb0 = copyRootBlock(true); +// m_rb1 = copyRootBlock(false); m_initialExtent = m_fileMetadata.file.length(); } - /** - * Return a copy of the current {@link IRootBlockView}. - * - * @param rb0 - * When <code>true</code> the view will be flagged as root block - * ZERO (0). Otherwise it is flagged as root block ONE (1). - * - * @return The {@link IRootBlockView}. - */ - private IRootBlockView copyRootBlock(final boolean rb0) { +// /** +// * Return a copy of the current {@link IRootBlockView}. +// * +// * @param rb0 +// * When <code>true</code> the view will be flagged as root block +// * ZERO (0). Otherwise it is flagged as root block ONE (1). +// * +// * @return The {@link IRootBlockView}. +// */ +// private IRootBlockView copyRootBlock(final boolean rb0) { +// +// final IRootBlockView rbv = new RootBlockView(rb0, m_rb.getOffsetBits(), +// m_rb.getNextOffset(), m_rb.getFirstCommitTime(), m_rb +// .getLastCommitTime(), m_rb.getCommitCounter(), m_rb +// .getCommitRecordAddr(), +// m_rb.getCommitRecordIndexAddr(), m_fileMetadata.rootBlock +// .getUUID(), m_rb.getQuorumToken(), m_rb +// .getMetaStartAddr(), m_rb.getMetaBitsAddr(), +// StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), +// m_rb.getCloseTime(), s_ckutil); +// +// return rbv; +// } - final IRootBlockView rbv = new RootBlockView(rb0, m_rb.getOffsetBits(), - m_rb.getNextOffset(), m_rb.getFirstCommitTime(), m_rb - .getLastCommitTime(), m_rb.getCommitCounter(), m_rb - .getCommitRecordAddr(), - m_rb.getCommitRecordIndexAddr(), m_fileMetadata.rootBlock - .getUUID(), m_rb.getQuorumToken(), m_rb - .getMetaStartAddr(), m_rb.getMetaBitsAddr(), - StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), - m_rb.getCloseTime(), s_ckutil); - - return rbv; - } - /** * Create a wrapper to circumvent package visibility issues since we'd like * to keep RWStore in a separate package @@ -164,10 +155,10 @@ interface IFileMetadataView { IRootBlockView getRootBlock(); - IRootBlockView getRootBlock0(); +// IRootBlockView getRootBlock0(); +// +// IRootBlockView getRootBlock1(); - IRootBlockView getRootBlock1(); - File getFile(); RandomAccessFile getRandomAccessFile(); @@ -177,7 +168,7 @@ long commitRecordIndexAddr, long metaStartAddr, long metaBitsAddr, long closeTime); } - static final ChecksumUtility s_ckutil = new ChecksumUtility(); + static final private ChecksumUtility s_ckutil = new ChecksumUtility(); public class FileMetadataView implements IFileMetadataView { @@ -188,14 +179,14 @@ return m_rb; } - public IRootBlockView getRootBlock0() { - return m_rb0; - } +// public IRootBlockView getRootBlock0() { +// return m_rb0; +// } +// +// public IRootBlockView getRootBlock1() { +// return m_rb1; +// } - public IRootBlockView getRootBlock1() { - return m_rb1; - } - public FileMetadata getFileMetadata() { return m_fileMetadata; } @@ -232,21 +223,22 @@ } } - public ByteBuffer readRootBlock(final boolean rootBlock0) { + public ByteBuffer readRootBlock(final boolean rootBlock0) { - checkReopen(); - - IRootBlockView rbv = rootBlock0 ? m_rb0 : m_rb1; - - return rbv.asReadOnlyBuffer(); + if (!isOpen()) + throw new IllegalStateException(); + + return m_store.readRootBlock(rootBlock0); + } public ByteBuffer read(final long addr) { - checkReopen(); + if (!isOpen()) + throw new IllegalStateException(); - int rwaddr = decodeAddr(addr); - int sze = decodeSize(addr); + final int rwaddr = decodeAddr(addr); + final int sze = decodeSize(addr); if (rwaddr == 0L || sze == 0) { throw new IllegalArgumentException(); @@ -256,7 +248,8 @@ * Allocate buffer to include checksum to allow single read * but then return ByteBuffer excluding those bytes */ - byte buf[] = new byte[sze+4]; // 4 bytes for checksum + final byte buf[] = new byte[sze+4]; // 4 bytes for checksum + m_store.getData(rwaddr, buf); return ByteBuffer.wrap(buf, 0, sze); @@ -270,7 +263,8 @@ public long write(final ByteBuffer data, final IAllocationContext context) { - checkReopen(); + if (!isOpen()) + throw new IllegalStateException(); if (data == null) throw new IllegalArgumentException(); @@ -287,44 +281,32 @@ throw new AssertionError(); } - final int nbytes = data.remaining(); - - if (nbytes == 0) - throw new IllegalArgumentException(); - - try { - - final long rwaddr = m_store.alloc(data.array(), nbytes, context); - - data.position(nbytes); // update position to end of buffer - - final long retaddr = encodeAddr(rwaddr, nbytes); + final int nbytes = data.remaining(); - return retaddr; + if (nbytes == 0) + throw new IllegalArgumentException(); - } catch (RuntimeException re) { - - log.error(re,re);//re.printStackTrace(); - - m_needsReopen = true; - - reopen(); // FIXME + final long rwaddr = m_store.alloc(data.array(), nbytes, context); - throw re; - } - } + data.position(nbytes); // update position to end of buffer - private void checkReopen() { - if (m_needsReopen) { - assert false; - - if (m_needsReopen) { - // reopen(); // should be handled by RWStore - m_needsReopen = false; - } - } - } + final long retaddr = encodeAddr(rwaddr, nbytes); + return retaddr; + + } + +// private void checkReopen() { +// if (m_needsReopen) { +// assert false; +// +// if (m_needsReopen) { +// // reopen(); // should be handled by RWStore +// m_needsReopen = false; +// } +// } +// } + // public long allocate(int nbytes) { // return encodeAddr(m_store.alloc(nbytes), nbytes); // } @@ -406,27 +388,37 @@ } public int getHeaderSize() { + return FileMetadata.headerSize0; + } final private long m_initialExtent; - private volatile boolean m_needsReopen = false; +// private volatile boolean m_needsReopen = false; public long getInitialExtent() { - return m_initialExtent; + + return m_initialExtent; + } public long getMaximumExtent() { - return 0L; + + return 0L; + } public boolean useChecksums() { + return true; + } public long getNextOffset() { - return m_store.getNextOffset(); + + return m_store.getNextOffset(); + } public long getUserExtent() { @@ -457,39 +449,15 @@ public void writeRootBlock(final IRootBlockView rootBlock, final ForceEnum forceOnCommit) { - if (rootBlock == null) - throw new IllegalArgumentException(); + m_store.writeRootBlock(rootBlock, forceOnCommit); + + // Current rootBlock is retained + m_rb = rootBlock; +// if (m_rb.isRootBlock0()) +// m_rb0 = m_rb; +// else +// m_rb1 = m_rb; - try { - m_store.checkRootBlock(rootBlock); - - if (log.isTraceEnabled()) { - log.trace("Writing new rootblock with commitCounter: " - + rootBlock.getCommitCounter() - + ", commitRecordAddr: " + rootBlock.getCommitRecordAddr() - + ", commitRecordIndexAddr: " + rootBlock.getCommitRecordIndexAddr()); - } - - m_fileMetadata.writeRootBlock(rootBlock, forceOnCommit); - - // Current rootBlock is retained - m_rb = rootBlock; - if (m_rb.isRootBlock0()) - m_rb0 = m_rb; - else - m_rb1 = m_rb; - - } - - catch (IOException ex) { - m_needsReopen = true; - - reopen(); // force immediate reopen - - throw new RuntimeException(ex); - - } - } /** @@ -554,7 +522,7 @@ deleteResources(); } - public IRootBlockView getRootBlock() { + private IRootBlockView getRootBlock() { return m_fmv.newRootBlockView(!m_rb.isRootBlock0(), // m_rb.getOffsetBits(),// getNextOffset(), // @@ -587,59 +555,55 @@ * Calls through to store and then to WriteCacheService.reset */ public void abort() { - m_store.checkRootBlock(m_rb); - m_store.reset(); } - public void force(final boolean metadata) { - try { - m_store.flushWrites(metadata); - } catch (ClosedByInterruptException e) { - m_needsReopen = true; - - reopen(); // FIXME - - throw new RuntimeException(e); - } catch (IOException e) { - m_needsReopen = true; - - reopen(); // FIXME - - throw new RuntimeException(e); - } + public void force(final boolean metadata) { + + try { + + m_store.flushWrites(metadata); + + } catch (IOException e) { + + throw new RuntimeException(e); + + } + } - /** - * Must ensure that the writeCacheService is reset and direct buffers released. - * TODO: Modify so that current WriteCacheService is reset and re-used by new - * store. - */ - public void reopen() { - try { - log.warn("Request to reopen store after interrupt"); +// /** +// * Must ensure that the writeCacheService is reset and direct buffers released. +// * TODO: Modify so that current WriteCacheService is reset and re-used by new +// * store. +// */ +// public void reopen() { +// try { +// log.warn("Request to reopen store after interrupt"); +// +// m_store.close(); +// m_fileMetadata.raf = new RandomAccessFile(m_fileMetadata.file, +// m_fileMetadata.fileMode); +// m_store = new RWStore(m_fmv, false, m_environment); // never read-only for now +// m_needsReopen = false; +// m_open = true; +// } catch (Throwable t) { +// log.error(t,t); +// +// throw new RuntimeException(t); +// } +// } - m_store.close(); - m_fileMetadata.raf = new RandomAccessFile(m_fileMetadata.file, - m_fileMetadata.fileMode); - m_store = new RWStore(m_fmv, false, m_environment); // never read-only for now - m_needsReopen = false; - m_open = true; - } catch (Throwable t) { - log.error(t,t); - - throw new RuntimeException(t); - } - } - public File getFile() { - return m_fileMetadata.file; + + return m_fileMetadata.file; + } public Object getRandomAccessFile() { - checkReopen(); - return m_fileMetadata.raf; + return m_fileMetadata.raf; + } /** @@ -655,24 +619,33 @@ } public UUID getUUID() { - return m_fileMetadata.rootBlock.getUUID(); + + return m_fileMetadata.rootBlock.getUUID(); + } public boolean isFullyBuffered() { - return false; + + return false; + } public boolean isOpen() { - // return m_fileMetadata.raf != null && m_fileMetadata.raf.getChannel().isOpen(); - return m_open; + + return m_open; + } public boolean isReadOnly() { - return false; + + return false; + } public boolean isStable() { - return true; + + return true; + } /** @@ -768,19 +741,6 @@ return m_store.physicalAddress(rwaddr); } - /** - * Saves the current list of delete blocks, returning the address allocated. - * This can be used later to retrieve the addresses of allocations to be - * freed. - * - * @return the address of the delete blocks, or zero if none - */ - public long saveDeleteBlocks() { - - return m_store.saveDeferrals(); - - } - /* * IHABufferStrategy */ Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockView.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockView.java 2010-11-03 16:20:20 UTC (rev 3881) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockView.java 2010-11-03 17:09:11 UTC (rev 3882) @@ -101,6 +101,7 @@ static final transient short OFFSET_UUID = OFFSET_STORETYPE + Bytes.SIZEOF_BYTE; static final transient short OFFSET_CHALLIS1 = OFFSET_UUID + Bytes.SIZEOF_UUID; static final transient short OFFSET_CHECKSUM = OFFSET_CHALLIS1 + SIZEOF_TIMESTAMP; + public static final transient short SIZEOF_ROOT_BLOCK = OFFSET_CHECKSUM + SIZEOF_CHECKSUM; // Note: SIZEOF_ROOT_BLOCK := 340 Bytes. This is an invariant. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 16:20:20 UTC (rev 3881) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 17:09:11 UTC (rev 3882) @@ -57,12 +57,14 @@ import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.CommitRecordIndex; import com.bigdata.journal.CommitRecordSerializer; +import com.bigdata.journal.FileMetadata; import com.bigdata.journal.ForceEnum; import com.bigdata.journal.ICommitRecord; import com.bigdata.journal.IRootBlockView; import com.bigdata.journal.Journal; import com.bigdata.journal.JournalTransactionService; import com.bigdata.journal.Options; +import com.bigdata.journal.RootBlockView; import com.bigdata.journal.RWStrategy.FileMetadataView; import com.bigdata.quorum.Quorum; import com.bigdata.util.ChecksumUtility; @@ -427,8 +429,6 @@ m_rb = m_fmv.getRootBlock(); -// m_filename = m_fd.getAbsolutePath(); - m_commitList = new ArrayList<Allocator>(); m_allocs = new ArrayList<Allocator>(); @@ -551,7 +551,7 @@ * * @param rbv */ - public void checkRootBlock(final IRootBlockView rbv) { + private void checkRootBlock(final IRootBlockView rbv) { final long nxtOffset = rbv.getNextOffset(); final int nxtalloc = -(int) (nxtOffset >> 32); @@ -584,6 +584,8 @@ /** * Ensure rootblock is in sync with external request + * + * FIXME No side-effect please. */ m_rb = rbv; } @@ -1471,6 +1473,7 @@ } m_allocationLock.lock(); try { + checkRootBlock(m_rb); m_commitList.clear(); m_allocs.clear(); m_freeBlobs.clear(); @@ -1547,51 +1550,51 @@ static final float s_version = 3.0f; - /** - * This must now update the root block which is managed by FileMetadata in - * almost guaranteed secure manner. - * - * It is not the responsibility of the store to write this out, this is - * handled by whatever is managing the FileMetadata that this RWStore was - * initialised from and should be forced by newRootBlockView. - * - * It should now only be called by extend file to ensure that the metaBits - * are set correctly. - * - * In order to ensure that the new block is the one that would be chosen, we need to - * duplicate the rootBlock. This does mean that we lose the ability to roll - * back the commit. It also means that until that point there is an invalid store state. - * Both rootBlocks would be valid but with different extents. This is fine at - * that moment, but subsequent writes would effectively cause the initial rootBlock - * to reference invalid allocation blocks. - * - * In any event we need to duplicate the rootblocks since any rootblock that references - * the old allocation area will be invalid. - * - * TODO: Should be replaced with specific updateExtendedMetaData that will - * simply reset the metaBitsAddr - * @throws IOException - */ - protected void writeFileSpec() throws IOException { +// /** +// * This must now update the root block which is managed by FileMetadata in +// * almost guaranteed secure manner. +// * +// * It is not the responsibility of the store to write this out, this is +// * handled by whatever is managing the FileMetadata that this RWStore was +// * initialised from and should be forced by newRootBlockView. +// * +// * It should now only be called by extend file to ensure that the metaBits +// * are set correctly. +// * +// * In order to ensure that the new block is the one that would be chosen, we need to +// * duplicate the rootBlock. This does mean that we lose the ability to roll +// * back the commit. It also means that until that point there is an invalid store state. +// * Both rootBlocks would be valid but with different extents. This is fine at +// * that moment, but subsequent writes would effectively cause the initial rootBlock +// * to reference invalid allocation blocks. +// * +// * In any event we need to duplicate the rootblocks since any rootblock that references +// * the old allocation area will be invalid. +// * +// * TODO: Should be replaced with specific updateExtendedMetaData that will +// * simply reset the metaBitsAddr +// * @throws IOException +// */ +// protected void writeFileSpec() throws IOException { +// +// m_rb = m_fmv.newRootBlockView(// +// !m_rb.isRootBlock0(), // +// m_rb.getOffsetBits(), // +// getNextOffset(), // +// m_rb.getFirstCommitTime(),// +// m_rb.getLastCommitTime(), // +// m_rb.getCommitCounter(), // +// m_rb.getCommitRecordAddr(),// +// m_rb.getCommitRecordIndexAddr(), // +// getMetaStartAddr(),// +// getMetaBitsAddr(), // +// m_rb.getLastCommitTime()// +// ); +// +// m_fmv.getFileMetadata().writeRootBlock(m_rb, ForceEnum.Force); +// +// } - m_rb = m_fmv.newRootBlockView(// - !m_rb.isRootBlock0(), // - m_rb.getOffsetBits(), // - getNextOffset(), // - m_rb.getFirstCommitTime(),// - m_rb.getLastCommitTime(), // - m_rb.getCommitCounter(), // - m_rb.getCommitRecordAddr(),// - m_rb.getCommitRecordIndexAddr(), // - getMetaStartAddr(),// - getMetaBitsAddr(), // - m_rb.getLastCommitTime()// - ); - - m_fmv.getFileMetadata().writeRootBlock(m_rb, ForceEnum.Force); - - } - // float m_vers = 0.0f; // // protected void readFileSpec() { @@ -2614,18 +2617,6 @@ } -// /** -// * Hook used by the unit tests to destroy their test files. -// */ -// public void destroy() { -// try { -// raf.close(); -// } catch (IOException e) { -// if (!file.delete()) -// log.warn("Could not delete file: " + file); -// } -// } - synchronized public FileChannel reopenChannel() throws IOException { if (raf != null && raf.getChannel().isOpen()) { @@ -2794,14 +2785,19 @@ // } // } - /** - * Writes the content of currentTxnFreeList to the store. - * - * These are the current buffered frees that have yet been saved into - * a block referenced from the deferredFreeList - * - * @return the address of the deferred addresses saved on the store - */ + /** + * Saves the current list of delete blocks, returning the address allocated. + * This can be used later to retrieve the addresses of allocations to be + * freed. + * + * Writes the content of currentTxnFreeList to the store. + * + * These are the current buffered frees that have yet been saved into a + * block referenced from the deferredFreeList + * + * @return the address of the deferred addresses saved on the store, or zero + * if none. + */ public long saveDeferrals() { m_allocationLock.lock(); try { @@ -3082,4 +3078,119 @@ } + public void writeRootBlock(final IRootBlockView rootBlock, + final ForceEnum forceOnCommit) { + + if (rootBlock == null) + throw new IllegalArgumentException(); + + checkRootBlock(rootBlock); + + if (log.isTraceEnabled()) { + log.trace("Writing new rootblock with commitCounter: " + + rootBlock.getCommitCounter() + ", commitRecordAddr: " + + rootBlock.getCommitRecordAddr() + + ", commitRecordIndexAddr: " + + rootBlock.getCommitRecordIndexAddr()); + } + + try { + + final ByteBuffer data = rootBlock.asReadOnlyBuffer(); + + final long pos = rootBlock.isRootBlock0() + ? FileMetadata.OFFSET_ROOT_BLOCK0 + : FileMetadata.OFFSET_ROOT_BLOCK1; + + /* + * Note: This uses the [opener] to automatically retry the operation + * in case concurrent readers are interrupting, causing an + * asynchronous close of the backing channel. + * + * @todo Consider using the read lock vs the write lock of the + * extensionLock here. The advantage of the read lock is higher + * concurrency. The advantage of the write lock is that it locks out + * readers when we are writing the root blocks, which could help to + * ensure timely updates of the root blocks even if readers are + * behaving badly (lots of interrupts). + * + * FIXME Modify AbstractInterruptsTestCase to test for correct + * handling of root block writes where concurrent readers cause the + * backing store to be closed asynchronously. This code block SHOULD + * cause the root block write to eventually succeed. + */ + final Lock lock = m_extensionLock.readLock(); + lock.lock(); + try { + + // Update the root block. + FileChannelUtility.writeAll(m_reopener, data, pos); + + /* + * Generally, you want to force the file data to the disk here. + * The file metadata MIGHT not matter since we always force it + * to the disk when we change the file size (unless the file + * system updates other aspects of file metadata during normal + * writes). + * + * @todo make sure the journal has already forced the writes, + * that forcing an empty cache buffer is a NOP, and that we want + * to just force the channel after we write the root blocks + * since writes were already forced on each node in the quorum + * before we wrote the root blocks and the root blocks are + * transmitted using RMI not the write pipeline. + */ + + // sync the disk. + m_reopener.reopenChannel().force(forceOnCommit == ForceEnum.ForceMetadata); + +// // Update counters. +// final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() +// .acquire(); +// try { +// c.nwriteRootBlock++; +// } finally { +// c.release(); +// } + + } finally { + + lock.unlock(); + + } + + } catch (IOException ex) { + + throw new RuntimeException(ex); + + } + + if (log.isDebugEnabled()) + log.debug("wrote root block: "+rootBlock); + + } + + public ByteBuffer readRootBlock(final boolean rootBlock0) { + + final ByteBuffer tmp = ByteBuffer + .allocate(RootBlockView.SIZEOF_ROOT_BLOCK); + + try { + + FileChannelUtility.readAll(m_reopener, tmp, + rootBlock0 ? FileMetadata.OFFSET_ROOT_BLOCK0 + : FileMetadata.OFFSET_ROOT_BLOCK1); + + tmp.position(0); // resets the position. + + } catch (IOException ex) { + + throw new RuntimeException(ex); + + } + + return tmp; + + } + } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 16:20:20 UTC (rev 3881) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 17:09:11 UTC (rev 3882) @@ -415,7 +415,7 @@ */ public void test_allocations() { - final Journal store = (Journal) getStore(); + Journal store = (Journal) getStore(); try { @@ -436,7 +436,8 @@ store.commit(); // Confirm that we can re-open the journal after commit - bufferStrategy.reopen(); + store = (Journal) reopenStore(store); + } finally { store.destroy(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-03 18:00:58
|
Revision: 3883 http://bigdata.svn.sourceforge.net/bigdata/?rev=3883&view=rev Author: thompsonbry Date: 2010-11-03 18:00:50 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Sync to Martyn. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-11-03 17:09:11 UTC (rev 3882) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-11-03 18:00:50 UTC (rev 3883) @@ -83,7 +83,7 @@ /** * The file that was opened. */ - final File file; + public final File file; /** * The mode used to open the file. @@ -104,6 +104,17 @@ */ RandomAccessFile raf; + /** + * The interface for IO performed on that file. + * <p> + * Note: this method is only safe for use during the initial file + * create/open. It is not safe to use once a file has been closed, whether + * directly or by an interrupt during an IO operation. + */ + public RandomAccessFile getRandomAccessFile() { + return raf; + } + /** * The 32-bit magic value at offset 0L in the file. * @@ -172,7 +183,7 @@ /** * True iff the file was opened in a read-only mode. */ - final boolean readOnly; + public final boolean readOnly; /** * The timestamp from the createTime field in the root block. @@ -233,13 +244,13 @@ * The current root block. For a new file, this is "rootBlock0". For an * existing file it is based on an examination of both root blocks. */ - final IRootBlockView rootBlock; + public final IRootBlockView rootBlock; /** * Properties used to initialize this FileMetadata object */ final Properties properties; - + /** * This constructor handles the case where the file does not exist or exists * but is empty (including files created by the temporary file creation Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 17:09:11 UTC (rev 3882) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 18:00:50 UTC (rev 3883) @@ -41,26 +41,25 @@ import com.bigdata.rawstore.IAddressManager; import com.bigdata.rwstore.IAllocationContext; import com.bigdata.rwstore.RWStore; -import com.bigdata.util.ChecksumUtility; /** * The hook that accesses the RWStore to provide read/write services as opposed - * to the WORM characteristics of the DiskOnlyStrategy AddressManager + * to the WORM characteristics of the DiskOnlyStrategy AddressManager. * - * The intent behind this approach is to try to manage the protocol - * differences between the IStore implementation, assumed as a backing - * service to the CTC ObjectManager, and an IBufferStrategy service for a - * BigData Journal. + * The intent behind this approach is to try to manage the protocol differences + * between the IStore implementation, assumed as a backing service to the CTC + * ObjectManager, and an IBufferStrategy service for a BigData Journal. * * The most fundamental difference is with the root data, with RootBlock - * including both low-level store data - such as metabits info - and - * higher level, journal maintained data. + * including both low-level store data - such as metabits info - and higher + * level, journal maintained data. * - * TODO: Rationalise rootBlock access - use rootblock held by RWStore + * @author Martyn Cutcher * - * TODO: Implement use of IByteArraySlice as alternative to ByteBuffer + * @todo review life cycle state changes and refusal of methods when the backing + * store is closed. * - * @author Martyn Cutcher + * @todo Implement use of IByteArraySlice as alternative to ByteBuffer */ public class RWStrategy extends AbstractRawStore implements IBufferStrategy, IHABufferStrategy { @@ -68,25 +67,26 @@ private final IAddressManager m_am = new RWAddressManager(); - final private FileMetadata m_fileMetadata; - -// final private Quorum<?,?> m_environment; - /** - * The backing store impl. - * - * @see #reopen(). + * The backing store implementation. */ - private volatile RWStore m_store = null; + private final RWStore m_store; - final private FileMetadataView m_fmv = new FileMetadataView(); - + /** + * The {@link UUID} for the store. + */ + private final UUID m_uuid; + + /** + * <code>true</code> iff the backing store is open. + */ private volatile boolean m_open = false; - - private volatile IRootBlockView m_rb; -// private volatile IRootBlockView m_rb0; -// private volatile IRootBlockView m_rb1; + /** + * The size of the backing file when it was opened by the constructor. + */ + final private long m_initialExtent; + /** * @todo The use of this lock is suspicious. It is only used by * {@link #commit(IJournal)} and that method is invoked by the @@ -103,126 +103,16 @@ */ RWStrategy(final FileMetadata fileMetadata, final Quorum<?,?> quorum) { - m_fileMetadata = fileMetadata; + m_uuid = fileMetadata.rootBlock.getUUID(); + + m_store = new RWStore(fileMetadata, quorum); -// m_environment = quorum; - - m_rb = fileMetadata.rootBlock; - - m_store = new RWStore(m_fmv, false/*readOnly*/, quorum); // not read-only for now m_open = true; - - m_rb = getRootBlock(); // ensure values correct from create/reopen - -// m_rb0 = copyRootBlock(true); -// m_rb1 = copyRootBlock(false); - - m_initialExtent = m_fileMetadata.file.length(); + + m_initialExtent = fileMetadata.file.length(); } -// /** -// * Return a copy of the current {@link IRootBlockView}. -// * -// * @param rb0 -// * When <code>true</code> the view will be flagged as root block -// * ZERO (0). Otherwise it is flagged as root block ONE (1). -// * -// * @return The {@link IRootBlockView}. -// */ -// private IRootBlockView copyRootBlock(final boolean rb0) { -// -// final IRootBlockView rbv = new RootBlockView(rb0, m_rb.getOffsetBits(), -// m_rb.getNextOffset(), m_rb.getFirstCommitTime(), m_rb -// .getLastCommitTime(), m_rb.getCommitCounter(), m_rb -// .getCommitRecordAddr(), -// m_rb.getCommitRecordIndexAddr(), m_fileMetadata.rootBlock -// .getUUID(), m_rb.getQuorumToken(), m_rb -// .getMetaStartAddr(), m_rb.getMetaBitsAddr(), -// StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), -// m_rb.getCloseTime(), s_ckutil); -// -// return rbv; -// } - - /** - * Create a wrapper to circumvent package visibility issues since we'd like - * to keep RWStore in a separate package - * - * @author mgc - * - */ - interface IFileMetadataView { - IRootBlockView getRootBlock(); - -// IRootBlockView getRootBlock0(); -// -// IRootBlockView getRootBlock1(); - - File getFile(); - - RandomAccessFile getRandomAccessFile(); - - public IRootBlockView newRootBlockView(boolean rootBlock0, int offsetBits, long nextOffset, - long firstCommitTime, long lastCommitTime, long commitCounter, long commitRecordAddr, - long commitRecordIndexAddr, long metaStartAddr, long metaBitsAddr, long closeTime); - } - - static final private ChecksumUtility s_ckutil = new ChecksumUtility(); - - public class FileMetadataView implements IFileMetadataView { - - private FileMetadataView() { - } - - public IRootBlockView getRootBlock() { - return m_rb; - } - -// public IRootBlockView getRootBlock0() { -// return m_rb0; -// } -// -// public IRootBlockView getRootBlock1() { -// return m_rb1; -// } - - public FileMetadata getFileMetadata() { - return m_fileMetadata; - } - - public File getFile() { - return m_fileMetadata.file; - } - - public RandomAccessFile getRandomAccessFile() { - return m_fileMetadata.raf; - } - - public IRootBlockView newRootBlockView(boolean rootBlock0, - int offsetBits, long nextOffset, long firstCommitTime, - long lastCommitTime, long commitCounter, long commitRecordAddr, - long commitRecordIndexAddr, long metaStartAddr, - long metaBitsAddr, long closeTime) { - - final IRootBlockView rbv = new RootBlockView(rootBlock0, - offsetBits, nextOffset, firstCommitTime, lastCommitTime, - commitCounter, commitRecordAddr, commitRecordIndexAddr, - m_fileMetadata.rootBlock.getUUID(), - -1 /* FIXME: quorumToken */, metaStartAddr, metaBitsAddr, - StoreTypeEnum.RW, m_fileMetadata.rootBlock.getCreateTime(), - closeTime, s_ckutil); - - // writeRootBlock(rbv, ForceEnum.Force); // not sure if this is really needed now! - - return rbv; - } - - public String getProperty(String name, String defvalue) { - return m_fileMetadata.getProperty(name, defvalue); - } - } - public ByteBuffer readRootBlock(final boolean rootBlock0) { if (!isOpen()) @@ -296,21 +186,6 @@ } -// private void checkReopen() { -// if (m_needsReopen) { -// assert false; -// -// if (m_needsReopen) { -// // reopen(); // should be handled by RWStore -// m_needsReopen = false; -// } -// } -// } - -// public long allocate(int nbytes) { -// return encodeAddr(m_store.alloc(nbytes), nbytes); -// } - private long encodeAddr(long alloc, final int nbytes) { alloc <<= 32; alloc += nbytes; @@ -383,7 +258,7 @@ public long getExtent() { - return this.m_fileMetadata.file.length(); + return m_store.getStoreFile().length(); } @@ -393,10 +268,6 @@ } - final private long m_initialExtent; - -// private volatile boolean m_needsReopen = false; - public long getInitialExtent() { return m_initialExtent; @@ -450,13 +321,6 @@ final ForceEnum forceOnCommit) { m_store.writeRootBlock(rootBlock, forceOnCommit); - - // Current rootBlock is retained - m_rb = rootBlock; -// if (m_rb.isRootBlock0()) -// m_rb0 = m_rb; -// else -// m_rb1 = m_rb; } @@ -464,81 +328,43 @@ * Set close time in rootBlock, and close file */ public void close() { - if (m_fileMetadata.raf == null) { + if (!m_open) { throw new IllegalStateException(); } - try { - m_open = false; - - m_store.close(); - m_fileMetadata.raf.close(); - m_fileMetadata.raf = null; - } catch (IOException e) { - log.error(e,e);//e.printStackTrace(); - } + m_store.close(); + m_open = false; } - public void deleteResources() { - - if (m_fileMetadata.raf != null - && m_fileMetadata.raf.getChannel().isOpen()) { + public void deleteResources() { - throw new IllegalStateException("Backing store is open: " - + m_fileMetadata.file); - - } + if (m_open) + throw new IllegalArgumentException(); - if (m_fileMetadata.file.exists()) { - - try { - - if (!m_fileMetadata.file.delete()) { - - log.warn("Unable to delete file: " + m_fileMetadata.file); - - } + final File file = m_store.getStoreFile(); - } catch (SecurityException e) { - - log.warn("Problem deleting file", e); - + if (file.exists()) { + + if (!file.delete()) { + + log.warn("Unable to delete file: " + file); + } } - + } public void destroy() { - m_store.close(); - if (m_fileMetadata.raf != null && m_fileMetadata.raf.getChannel().isOpen()) { - try { - m_fileMetadata.raf.close(); - } catch (IOException e) { - log.warn("Problem with file close", e); - } - } - + m_store.close(); + m_open = false; + deleteResources(); + } - private IRootBlockView getRootBlock() { - return m_fmv.newRootBlockView(!m_rb.isRootBlock0(), // - m_rb.getOffsetBits(),// - getNextOffset(), // - m_rb.getFirstCommitTime(),// - m_rb.getLastCommitTime(), // - m_rb.getCommitCounter(),// - m_rb.getCommitRecordAddr(), // - m_rb.getCommitRecordIndexAddr(), // - getMetaStartAddr(),// - getMetaBitsAddr(), // - m_rb.getCloseTime()// - ); - } - /** - * commit must use a commit lock to synchronize the rootBlock with the commit. + * Commit must use a commit lock to synchronize the rootBlock with the commit. * * Must pass in earliestTxnTime to commitChanges to enable */ @@ -555,7 +381,9 @@ * Calls through to store and then to WriteCacheService.reset */ public void abort() { + m_store.reset(); + } public void force(final boolean metadata) { @@ -571,40 +399,12 @@ } } - -// /** -// * Must ensure that the writeCacheService is reset and direct buffers released. -// * TODO: Modify so that current WriteCacheService is reset and re-used by new -// * store. -// */ -// public void reopen() { -// try { -// log.warn("Request to reopen store after interrupt"); -// -// m_store.close(); -// m_fileMetadata.raf = new RandomAccessFile(m_fileMetadata.file, -// m_fileMetadata.fileMode); -// m_store = new RWStore(m_fmv, false, m_environment); // never read-only for now -// m_needsReopen = false; -// m_open = true; -// } catch (Throwable t) { -// log.error(t,t); -// -// throw new RuntimeException(t); -// } -// } - + public File getFile() { - return m_fileMetadata.file; + return m_store.getStoreFile(); } - - public Object getRandomAccessFile() { - - return m_fileMetadata.raf; - - } /** * Not supported - this is available on the {@link AbstractJournal}. @@ -620,7 +420,7 @@ public UUID getUUID() { - return m_fileMetadata.rootBlock.getUUID(); + return m_uuid; } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-11-03 17:09:11 UTC (rev 3882) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-11-03 18:00:50 UTC (rev 3883) @@ -39,19 +39,26 @@ * Maintains List of AllocBlock(s) */ public class FixedAllocator implements Allocator { - protected static final Logger log = Logger.getLogger(FixedAllocator.class); + + private static final Logger log = Logger.getLogger(FixedAllocator.class); - private RWWriteCacheService m_writeCache = null; + final private RWWriteCacheService m_writeCache; volatile private int m_freeBits; volatile private int m_freeTransients; - private int m_diskAddr; - int m_index; + /** + * Address of the {@link FixedAllocator} within the meta allocation space on + * the disk. + */ + volatile private int m_diskAddr; + volatile private int m_index; - public void setIndex(int index) { - AllocBlock fb = (AllocBlock) m_allocBlocks.get(0); - if (log.isDebugEnabled()) - log.debug("Restored index " + index + " with " + getStartAddr() + "[" + fb.m_bits[0] + "] from " + m_diskAddr); + public void setIndex(final int index) { + final AllocBlock fb = (AllocBlock) m_allocBlocks.get(0); + + if (log.isDebugEnabled()) + log.debug("Restored index " + index + " with " + getStartAddr() + + "[" + fb.m_bits[0] + "] from " + m_diskAddr); m_index = index; } @@ -60,12 +67,16 @@ return RWStore.convertAddr(m_startAddr); } - public int compareTo(Object o) { - Allocator other = (Allocator) o; + /* + * Note: Object#equals() is fine with this compareTo() implementation. It is + * only used to sort the allocators. + */ + public int compareTo(final Object o) { + final Allocator other = (Allocator) o; if (other.getStartAddr() == 0) { return -1; } else { - long val = getStartAddr() - other.getStartAddr(); + final long val = getStartAddr() - other.getStartAddr(); if (val == 0) { throw new Error("Two allocators at same address"); @@ -79,30 +90,32 @@ return m_diskAddr; } - public void setDiskAddr(int addr) { + public void setDiskAddr(final int addr) { m_diskAddr = addr; } - /** - * The tweek of 3 to the offset is to ensure 1, that no address is zero and 2 to enable - * the values 1 & 2 to be special cased (this aspect is now historical). - */ + /** + * The tweak of 3 to the offset is to ensure 1, that no address is zero and + * 2 to enable the values 1 & 2 to be special cased (this aspect is now + * historical). + */ public long getPhysicalAddress(int offset) { offset -= 3; - int allocBlockRange = 32 * m_bitSize; + final int allocBlockRange = 32 * m_bitSize; - AllocBlock block = (AllocBlock) m_allocBlocks.get(offset / allocBlockRange); - int bit = offset % allocBlockRange; + final AllocBlock block = (AllocBlock) m_allocBlocks.get(offset / allocBlockRange); + final int bit = offset % allocBlockRange; + if (RWStore.tstBit(block.m_bits, bit)) { - return RWStore.convertAddr(block.m_addr) + m_size * bit; + return RWStore.convertAddr(block.m_addr) + ((long)m_size * bit); } else { return 0L; } } - public int getPhysicalSize(int offset) { + public int getPhysicalSize(final int offset) { return m_size; } @@ -122,7 +135,7 @@ } volatile private IAllocationContext m_context; - public void setAllocationContext(IAllocationContext context) { + public void setAllocationContext(final IAllocationContext context) { if (context == null && m_context != null) { // restore commit bits in AllocBlocks for (AllocBlock allocBlock : m_allocBlocks) { @@ -150,39 +163,43 @@ log.debug("writing allocator " + m_index + " for " + getStartAddr() + " with " + fb.m_bits[0]); final byte[] buf = new byte[1024]; final DataOutputStream str = new DataOutputStream(new FixedOutputStream(buf)); + try { + str.writeInt(m_size); - str.writeInt(m_size); + final Iterator<AllocBlock> iter = m_allocBlocks.iterator(); + while (iter.hasNext()) { + final AllocBlock block = iter.next(); - final Iterator<AllocBlock> iter = m_allocBlocks.iterator(); - while (iter.hasNext()) { - final AllocBlock block = iter.next(); + str.writeInt(block.m_addr); + for (int i = 0; i < m_bitSize; i++) { + str.writeInt(block.m_bits[i]); + } - str.writeInt(block.m_addr); - for (int i = 0; i < m_bitSize; i++) { - str.writeInt(block.m_bits[i]); - } + if (!m_store.isSessionPreserved()) { + block.m_transients = block.m_bits.clone(); + } - if (!m_store.isSessionPreserved()) { - block.m_transients = block.m_bits.clone(); - } + /** + * If this allocator is shadowed then copy the new committed + * state to m_saveCommit + */ + if (m_context != null) { + assert block.m_saveCommit != null; - /** - * If this allocator is shadowed then copy the new - * committed state to m_saveCommit - */ - if (m_context != null) { - assert block.m_saveCommit != null; - - block.m_saveCommit = block.m_bits.clone(); - } else if (m_store.isSessionPreserved()) { - block.m_commit = block.m_transients.clone(); - } else { - block.m_commit = block.m_bits.clone(); - } + block.m_saveCommit = block.m_bits.clone(); + } else if (m_store.isSessionPreserved()) { + block.m_commit = block.m_transients.clone(); + } else { + block.m_commit = block.m_bits.clone(); + } + } + // add checksum + final int chk = ChecksumUtility.getCHK().checksum(buf, + str.size()); + str.writeInt(chk); + } finally { + str.close(); } - // add checksum - final int chk = ChecksumUtility.getCHK().checksum(buf, str.size()); - str.writeInt(chk); if (!m_store.isSessionPreserved()) { m_freeBits += m_freeTransients; @@ -205,14 +222,14 @@ // read does not read in m_size since this is read to determine the class of // allocator - public void read(DataInputStream str) { + public void read(final DataInputStream str) { try { m_freeBits = 0; - Iterator iter = m_allocBlocks.iterator(); - int blockSize = m_bitSize * 32 * m_size; + final Iterator<AllocBlock> iter = m_allocBlocks.iterator(); + final int blockSize = m_bitSize * 32 * m_size; while (iter.hasNext()) { - AllocBlock block = (AllocBlock) iter.next(); + final AllocBlock block = iter.next(); block.m_addr = str.readInt(); for (int i = 0; i < m_bitSize; i++) { @@ -220,7 +237,7 @@ /** * Need to calc how many free blocks are available, minor - * optimisation by checking against either empty or full to + * optimization by checking against either empty or full to * avoid scanning every bit unnecessarily **/ if (block.m_bits[i] == 0) { // empty @@ -252,11 +269,11 @@ } - /**The size of the allocation slots in bytes.*/ - private final int m_size; + /** The size of the allocation slots in bytes. */ + private final int m_size; - int m_startAddr = 0; - int m_endAddr = 0; + private int m_startAddr = 0; + private int m_endAddr = 0; /** * The #of ints in the {@link AllocBlock}'s internal arrays. @@ -265,12 +282,12 @@ private final ArrayList<AllocBlock> m_allocBlocks; - private RWStore m_store; + final private RWStore m_store; /** * Calculating the number of ints (m_bitSize) cannot rely on a power of 2. Previously this * assumption was sufficient to guarantee a rounding on to an 64k boundary. However, now - * nints * 32 * 64 = 64K, so need multiple of 32 ints + * nints * 32 * 64 = 64K, so need multiple of 32 ints. * <p> * So, whatever multiple of 64, if we allocate a multiple of 32 ints we are guaranteed to be * on an 64K boundary. @@ -337,7 +354,7 @@ } sb.append(block.getStats(null) + "\r\n"); if (counter != null) - counter.addAndGet(block.getAllocBits() * m_size); + counter.addAndGet(block.getAllocBits() * (long) m_size); } return sb.toString(); @@ -561,8 +578,9 @@ * all reserved allocation blocks. */ public long getFileStorage() { - final long blockSize = 32 * m_bitSize * m_size; + final long blockSize = 32L * m_bitSize * m_size; + long allocated = getAllocatedBlocks(); allocated *= blockSize; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 17:09:11 UTC (rev 3882) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 18:00:50 UTC (rev 3883) @@ -65,7 +65,6 @@ import com.bigdata.journal.JournalTransactionService; import com.bigdata.journal.Options; import com.bigdata.journal.RootBlockView; -import com.bigdata.journal.RWStrategy.FileMetadataView; import com.bigdata.quorum.Quorum; import com.bigdata.util.ChecksumUtility; @@ -391,7 +390,7 @@ // private String m_filename; - private final FileMetadataView m_fmv; +// private final FileMetadataView m_fmv; private IRootBlockView m_rb; @@ -407,11 +406,14 @@ * @param readOnly * @param quorum * @throws InterruptedException + * + * @todo support read-only open. */ + public RWStore(final FileMetadata fileMetadata, final Quorum<?, ?> quorum) { - public RWStore(final FileMetadataView fileMetadataView, - final boolean readOnly, final Quorum<?, ?> quorum) { - + if (fileMetadata == null) + throw new IllegalArgumentException(); + m_metaBitsSize = cDefaultMetaBitsSize; m_metaBits = new int[m_metaBitsSize]; @@ -420,14 +422,12 @@ m_maxFileSize = 2 * 1024 * 1024; // 1gb max (mult by 128)!! m_quorum = quorum; - - m_fmv = fileMetadataView; - m_fd = m_fmv.getFile(); + m_fd = fileMetadata.file; - m_raf = m_fmv.getRandomAccessFile(); + m_raf = fileMetadata.getRandomAccessFile(); - m_rb = m_fmv.getRootBlock(); + m_rb = fileMetadata.rootBlock; m_commitList = new ArrayList<Allocator>(); @@ -447,7 +447,7 @@ m_bufferedWrite = null; } - final int buffers = m_fmv.getFileMetadata().writeCacheBufferCount; + final int buffers = fileMetadata.writeCacheBufferCount; if(log.isInfoEnabled()) log.info("RWStore using writeCacheService with buffers: " + buffers); @@ -474,16 +474,17 @@ try { - if (m_rb.getNextOffset() == 0) { // if zero then new file - String buckets = m_fmv.getProperty(Options.RW_ALLOCATIONS, null); + if (m_rb.getNextOffset() == 0) { // if zero then new file + final String buckets = fileMetadata.getProperty( + Options.RW_ALLOCATIONS, null/* default */); if (buckets == null) { m_allocSizes = DEFAULT_ALLOC_SIZES; } else { - String[] specs = buckets.split(","); + final String[] specs = buckets.split(","); m_allocSizes = new int[specs.length]; int prevSize = 0; for (int i = 0; i < specs.length; i++) { - int nxtSize = Integer.parseInt(specs[i]); + final int nxtSize = Integer.parseInt(specs[i]); if (nxtSize <= prevSize) throw new IllegalArgumentException("Invalid AllocSizes property"); m_allocSizes[i] = nxtSize; @@ -595,7 +596,7 @@ * * Rather than reading from file, instead reads from the current root block. * - * We use the rootBlock fields, nextOffset, metaStartAddr, metaBitsAddr + * We use the rootBlock fields, nextOffset, metaStartAddr, metaBitsAddr. * * metaBitsAddr indicates where the meta allocation bits are. * Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 17:09:11 UTC (rev 3882) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 18:00:50 UTC (rev 3883) @@ -157,7 +157,7 @@ assertEquals(Options.MAXIMUM_EXTENT, 0L/* soft limit for disk mode */, bufferStrategy .getMaximumExtent()); - assertNotNull("raf", bufferStrategy.getRandomAccessFile()); +// assertNotNull("raf", bufferStrategy.getRandomAccessFile()); assertEquals(Options.BUFFER_MODE, BufferMode.DiskRW, bufferStrategy .getBufferMode()); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-03 18:53:56
|
Revision: 3884 http://bigdata.svn.sourceforge.net/bigdata/?rev=3884&view=rev Author: thompsonbry Date: 2010-11-03 18:53:49 +0000 (Wed, 03 Nov 2010) Log Message: ----------- Handoff to Martyn. There are some issues with abort(), but everything else is looking quite good. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Added Paths: ----------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-11-03 18:00:50 UTC (rev 3883) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-11-03 18:53:49 UTC (rev 3884) @@ -974,51 +974,56 @@ * Check root blocks (magic, timestamps), choose root block, read * constants (slotSize, segmentId). */ - { - - final ChecksumUtility checker = validateChecksum ? ChecksumUtility.threadChk - .get() - : null; + final RootBlockUtility tmp = new RootBlockUtility(opener, file, + validateChecksum, alternateRootBlock); + this.rootBlock0 = tmp.rootBlock0; + this.rootBlock1 = tmp.rootBlock1; + this.rootBlock = tmp.rootBlock; +// { +// +// final ChecksumUtility checker = validateChecksum ? ChecksumUtility.threadChk +// .get() +// : null; +// +// // final FileChannel channel = raf.getChannel(); +// final ByteBuffer tmp0 = ByteBuffer.allocate(RootBlockView.SIZEOF_ROOT_BLOCK); +// final ByteBuffer tmp1 = ByteBuffer.allocate(RootBlockView.SIZEOF_ROOT_BLOCK); +// FileChannelUtility.readAll(opener, tmp0, OFFSET_ROOT_BLOCK0); +// FileChannelUtility.readAll(opener, tmp1, OFFSET_ROOT_BLOCK1); +// tmp0.position(0); // resets the position. +// tmp1.position(0); +// try { +// rootBlock0 = new RootBlockView(true, tmp0, checker); +// } catch (RootBlockException ex) { +// log.warn("Bad root block zero: " + ex); +// } +// try { +// rootBlock1 = new RootBlockView(false, tmp1, checker); +// } catch (RootBlockException ex) { +// log.warn("Bad root block one: " + ex); +// } +// if (rootBlock0 == null && rootBlock1 == null) { +// throw new RuntimeException( +// "Both root blocks are bad - journal is not usable: " +// + file); +// } +// if (alternateRootBlock) +// log.warn("Using alternate root block"); +// /* +// * Choose the root block based on the commit counter. +// * +// * Note: The commit counters MAY be equal. This will happen if +// * we rollback the journal and override the current root block +// * with the alternate root block. +// */ +// final long cc0 = rootBlock0==null?-1L:rootBlock0.getCommitCounter(); +// final long cc1 = rootBlock1==null?-1L:rootBlock1.getCommitCounter(); +// this.rootBlock = (cc0 > cc1 ? (alternateRootBlock ? rootBlock1 +// : rootBlock0) : (alternateRootBlock ? rootBlock0 +// : rootBlock1)); +// +// } - // final FileChannel channel = raf.getChannel(); - final ByteBuffer tmp0 = ByteBuffer.allocate(RootBlockView.SIZEOF_ROOT_BLOCK); - final ByteBuffer tmp1 = ByteBuffer.allocate(RootBlockView.SIZEOF_ROOT_BLOCK); - FileChannelUtility.readAll(opener, tmp0, OFFSET_ROOT_BLOCK0); - FileChannelUtility.readAll(opener, tmp1, OFFSET_ROOT_BLOCK1); - tmp0.position(0); // resets the position. - tmp1.position(0); - try { - rootBlock0 = new RootBlockView(true, tmp0, checker); - } catch (RootBlockException ex) { - log.warn("Bad root block zero: " + ex); - } - try { - rootBlock1 = new RootBlockView(false, tmp1, checker); - } catch (RootBlockException ex) { - log.warn("Bad root block one: " + ex); - } - if (rootBlock0 == null && rootBlock1 == null) { - throw new RuntimeException( - "Both root blocks are bad - journal is not usable: " - + file); - } - if (alternateRootBlock) - log.warn("Using alternate root block"); - /* - * Choose the root block based on the commit counter. - * - * Note: The commit counters MAY be equal. This will happen if - * we rollback the journal and override the current root block - * with the alternate root block. - */ - final long cc0 = rootBlock0.getCommitCounter(); - final long cc1 = rootBlock1.getCommitCounter(); - this.rootBlock = (cc0 > cc1 ? (alternateRootBlock ? rootBlock1 - : rootBlock0) : (alternateRootBlock ? rootBlock0 - : rootBlock1)); - - } - this.bufferMode = BufferMode.getDefaultBufferMode(rootBlock.getStoreType()); if (bufferMode.isFullyBuffered()) { @@ -1113,7 +1118,7 @@ } - } + } /** * Used to re-open the {@link FileChannel} in this class. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2010-11-03 18:00:50 UTC (rev 3883) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2010-11-03 18:53:49 UTC (rev 3884) @@ -218,7 +218,8 @@ * data. For most strategies the action is void since the client WORM DISK * strategy writes data as allocated. For the Read Write Strategy more data * must be managed as part of the protocol outside of the RootBlock, and - * this is the method that triggers that management. + * this is the method that triggers that management. The caller MUST provide + * appropriate synchronization. * * @param abstractJournal */ Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 18:00:50 UTC (rev 3883) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 18:53:49 UTC (rev 3884) @@ -29,7 +29,6 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.util.UUID; -import java.util.concurrent.locks.ReentrantLock; import org.apache.log4j.Logger; @@ -56,10 +55,9 @@ * * @author Martyn Cutcher * - * @todo review life cycle state changes and refusal of methods when the backing - * store is closed. - * - * @todo Implement use of IByteArraySlice as alternative to ByteBuffer + * FIXME Review life cycle state changes and refusal of methods when the + * backing store is closed. m_open should probably be moved into RWStore + * which could then expose an isOpen() method to be used by this class. */ public class RWStrategy extends AbstractRawStore implements IBufferStrategy, IHABufferStrategy { @@ -87,21 +85,12 @@ */ final private long m_initialExtent; - /** - * @todo The use of this lock is suspicious. It is only used by - * {@link #commit(IJournal)} and that method is invoked by the - * {@link AbstractJournal#commitNow(long)} which is already protected - * by a lock. - */ - private final ReentrantLock m_commitLock = new ReentrantLock(); - /** - * It is important to ensure that the RWStrategy keeps a check on the physical root blocks and uses - * to manage re-opening of the store. * * @param fileMetadata + * @param quorum */ - RWStrategy(final FileMetadata fileMetadata, final Quorum<?,?> quorum) { + RWStrategy(final FileMetadata fileMetadata, final Quorum<?, ?> quorum) { m_uuid = fileMetadata.rootBlock.getUUID(); @@ -143,6 +132,7 @@ m_store.getData(rwaddr, buf); return ByteBuffer.wrap(buf, 0, sze); + } public long write(final ByteBuffer data) { @@ -161,7 +151,7 @@ if (data.hasArray() && data.arrayOffset() != 0) { /* - * FIXME [data] is not always backed by an array, the array may not + * @todo [data] is not always backed by an array, the array may not * be visible (read-only), the array offset may not be zero, etc. * Try to drive the ByteBuffer into the RWStore.alloc() method * instead. @@ -200,7 +190,9 @@ } private int decodeSize(final long addr) { - return (int) (addr & 0xFFFFFFFF); + + return (int) (addr & 0xFFFFFFFF); + } public void delete(final long addr) { @@ -246,9 +238,10 @@ } /** - * FIXME Define and implement support for counters. The pattern for this - * method is to always return a new object so it may be attached to various - * points in hierarchies belonging to the caller. + * @todo Define and implement support for counters. The pattern for this + * method is to always return a new object so it may be attached to + * various points in hierarchies belonging to the caller. See the + * {@link WORMStrategy} for examples. */ public CounterSet getCounters() { @@ -363,18 +356,10 @@ } - /** - * Commit must use a commit lock to synchronize the rootBlock with the commit. - * - * Must pass in earliestTxnTime to commitChanges to enable - */ - public void commit(final IJournal journal) { - m_commitLock.lock(); - try { - m_store.commitChanges((Journal) journal); // includes a force(false) - } finally { - m_commitLock.unlock(); - } + public void commit(final IJournal journal) { + + m_store.commitChanges((Journal) journal); // includes a force(false) + } /** @@ -545,7 +530,9 @@ * IHABufferStrategy */ - // FIXME writeRawBuffer + /** + * Operation is not supported. + */ public void writeRawBuffer(HAWriteMessage msg, ByteBuffer b) throws IOException, InterruptedException { @@ -553,7 +540,9 @@ } - // FIXME readFromLocalStore + /** + * Operation is not supported. + */ public ByteBuffer readFromLocalStore(final long addr) throws InterruptedException { Added: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java (rev 0) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java 2010-11-03 18:53:49 UTC (rev 3884) @@ -0,0 +1,116 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + * Created on Nov 3, 2010 + */ + +package com.bigdata.journal; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; + +import org.apache.log4j.Logger; + +import com.bigdata.io.FileChannelUtility; +import com.bigdata.io.IReopenChannel; +import com.bigdata.util.ChecksumUtility; + +/** + * Utility class will read both root blocks of a file and indicate which one + * is current. + * + * @author <a href="mailto:tho...@us...">Bryan + * Thompson</a> + * @version $Id$ + */ +public class RootBlockUtility { + + private static final Logger log = Logger.getLogger(RootBlockUtility.class); + + /** + * The 1st root block. + */ + public IRootBlockView rootBlock0; + + /** + * The 2nd root block. + */ + public IRootBlockView rootBlock1; + + /** + * The current root block. For a new file, this is "rootBlock0". For an + * existing file it is based on an examination of both root blocks. + */ + public final IRootBlockView rootBlock; + + public RootBlockUtility(final IReopenChannel<FileChannel> opener, + final File file, final boolean validateChecksum, + final boolean alternateRootBlock) throws IOException { + + final ChecksumUtility checker = validateChecksum ? ChecksumUtility.threadChk + .get() + : null; + + final ByteBuffer tmp0 = ByteBuffer + .allocate(RootBlockView.SIZEOF_ROOT_BLOCK); + final ByteBuffer tmp1 = ByteBuffer + .allocate(RootBlockView.SIZEOF_ROOT_BLOCK); + FileChannelUtility.readAll(opener, tmp0, FileMetadata.OFFSET_ROOT_BLOCK0); + FileChannelUtility.readAll(opener, tmp1, FileMetadata.OFFSET_ROOT_BLOCK1); + tmp0.position(0); // resets the position. + tmp1.position(0); + try { + rootBlock0 = new RootBlockView(true, tmp0, checker); + } catch (RootBlockException ex) { + log.warn("Bad root block zero: " + ex); + } + try { + rootBlock1 = new RootBlockView(false, tmp1, checker); + } catch (RootBlockException ex) { + log.warn("Bad root block one: " + ex); + } + if (rootBlock0 == null && rootBlock1 == null) { + throw new RuntimeException( + "Both root blocks are bad - journal is not usable: " + file); + } + if (alternateRootBlock) + log.warn("Using alternate root block"); + /* + * Choose the root block based on the commit counter. + * + * Note: The commit counters MAY be equal. This will happen if we + * rollback the journal and override the current root block with the + * alternate root block. + */ + final long cc0 = rootBlock0 == null ? -1L : rootBlock0 + .getCommitCounter(); + final long cc1 = rootBlock1 == null ? -1L : rootBlock1 + .getCommitCounter(); + this.rootBlock = (cc0 > cc1 ? (alternateRootBlock ? rootBlock1 + : rootBlock0) : (alternateRootBlock ? rootBlock0 : rootBlock1)); + } + +} Property changes on: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 18:00:50 UTC (rev 3883) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 18:53:49 UTC (rev 3884) @@ -64,6 +64,7 @@ import com.bigdata.journal.Journal; import com.bigdata.journal.JournalTransactionService; import com.bigdata.journal.Options; +import com.bigdata.journal.RootBlockUtility; import com.bigdata.journal.RootBlockView; import com.bigdata.quorum.Quorum; import com.bigdata.util.ChecksumUtility; @@ -236,7 +237,7 @@ // /////////////////////////////////////////////////////////////////////////////////////// private final File m_fd; - private RandomAccessFile m_raf; +// private RandomAccessFile m_raf; // protected FileMetadata m_metadata; // protected int m_transactionCount; // private boolean m_committing; @@ -392,7 +393,7 @@ // private final FileMetadataView m_fmv; - private IRootBlockView m_rb; +// private volatile IRootBlockView m_rb; // volatile private long m_commitCounter; @@ -417,18 +418,18 @@ m_metaBitsSize = cDefaultMetaBitsSize; m_metaBits = new int[m_metaBitsSize]; + m_metaTransientBits = new int[m_metaBitsSize]; - + + // @todo Review maximum file size constraints - is this old stuff? m_maxFileSize = 2 * 1024 * 1024; // 1gb max (mult by 128)!! m_quorum = quorum; m_fd = fileMetadata.file; - m_raf = fileMetadata.getRandomAccessFile(); + final IRootBlockView m_rb = fileMetadata.rootBlock; - m_rb = fileMetadata.rootBlock; - m_commitList = new ArrayList<Allocator>(); m_allocs = new ArrayList<Allocator>(); @@ -436,6 +437,7 @@ m_freeBlobs = new ArrayList<BlobAllocator>(); try { + final RandomAccessFile m_raf = fileMetadata.getRandomAccessFile(); m_reopener = new ReopenFileChannel(m_fd, m_raf, "rw"); } catch (IOException e1) { throw new RuntimeException(e1); @@ -453,7 +455,7 @@ log.info("RWStore using writeCacheService with buffers: " + buffers); try { - m_writeCache = new RWWriteCacheService(buffers, m_raf.length(), + m_writeCache = new RWWriteCacheService(buffers, m_fd.length(), m_reopener, m_quorum) { public WriteCache newWriteCache(final ByteBuffer buf, @@ -511,7 +513,7 @@ m_fileSize = m_nextAllocation; } - m_raf.setLength(convertAddr(m_fileSize)); + m_reopener.raf.setLength(convertAddr(m_fileSize)); m_maxFixedAlloc = m_allocSizes[m_allocSizes.length-1]*64; m_minFixedAlloc = m_allocSizes[0]*64; @@ -520,7 +522,7 @@ } else { - initfromRootBlock(); + initfromRootBlock(m_rb); m_maxFixedAlloc = m_allocSizes[m_allocSizes.length-1]*64; m_minFixedAlloc = m_allocSizes[0]*64; @@ -541,7 +543,7 @@ m_bufferedWrite = null; } m_writeCache.close(); - m_raf.close(); + m_reopener.raf.close(); } catch (Throwable t) { throw new RuntimeException(t); } @@ -583,12 +585,12 @@ log.trace("m_allocation: " + nxtalloc + ", m_metaBitsAddr: " + metaBitsAddr + ", m_commitCounter: " + commitCounter); - /** - * Ensure rootblock is in sync with external request - * - * FIXME No side-effect please. - */ - m_rb = rbv; +// /** +// * Ensure rootblock is in sync with external request +// * +// * FIXME No side-effect please. +// */ +// m_rb = rbv; } /** @@ -609,7 +611,7 @@ * * @throws IOException */ - private void initfromRootBlock() throws IOException { + private void initfromRootBlock(final IRootBlockView m_rb) throws IOException { // m_rb = m_fmv.getRootBlock(); assert(m_rb != null); @@ -1334,7 +1336,7 @@ } } - int fixedAllocatorIndex(final int size) { + private int fixedAllocatorIndex(final int size) { int i = 0; int cmp = m_minFixedAlloc; @@ -1355,17 +1357,17 @@ return PSOutputStream.getNew(this, m_maxFixedAlloc, null); } - - /**************************************************************************** - * Called by PSOutputStream to make to actual allocation or directly by lower - * level API clients. - * <p> - * If the allocation is for greater than MAX_FIXED_ALLOC, then a PSOutputStream - * is used to manage the chained buffers. - * - * TODO: Instead of using PSOutputStream instead manage allocations written - * to the WriteCacheService, building BlobHeader as you go. - **/ + + /**************************************************************************** + * Called by PSOutputStream to make to actual allocation or directly by + * lower level API clients. + * <p> + * If the allocation is for greater than MAX_FIXED_ALLOC, then a + * PSOutputStream is used to manage the chained buffers. + * + * TODO: Instead of using PSOutputStream, manage allocations written to the + * WriteCacheService, building BlobHeader as you go. + **/ public long alloc(final byte buf[], final int size, final IAllocationContext context) { if (size > (m_maxFixedAlloc-4)) { if (size > (BLOB_FIXED_ALLOCS * (m_maxFixedAlloc-4))) @@ -1474,8 +1476,15 @@ } m_allocationLock.lock(); try { - checkRootBlock(m_rb); - m_commitList.clear(); + + final RootBlockUtility tmp = new RootBlockUtility(m_reopener, m_fd, + true/* validateChecksum */, false/* alternateRootBlock */); + + final IRootBlockView rootBlock = tmp.rootBlock; + + checkRootBlock(rootBlock); + + m_commitList.clear(); m_allocs.clear(); m_freeBlobs.clear(); @@ -1491,7 +1500,7 @@ throw new RuntimeException(e); } - initfromRootBlock(); + initfromRootBlock(rootBlock); // notify of current file length. m_writeCache.setExtent(convertAddr(m_fileSize)); @@ -1551,80 +1560,6 @@ static final float s_version = 3.0f; -// /** -// * This must now update the root block which is managed by FileMetadata in -// * almost guaranteed secure manner. -// * -// * It is not the responsibility of the store to write this out, this is -// * handled by whatever is managing the FileMetadata that this RWStore was -// * initialised from and should be forced by newRootBlockView. -// * -// * It should now only be called by extend file to ensure that the metaBits -// * are set correctly. -// * -// * In order to ensure that the new block is the one that would be chosen, we need to -// * duplicate the rootBlock. This does mean that we lose the ability to roll -// * back the commit. It also means that until that point there is an invalid store state. -// * Both rootBlocks would be valid but with different extents. This is fine at -// * that moment, but subsequent writes would effectively cause the initial rootBlock -// * to reference invalid allocation blocks. -// * -// * In any event we need to duplicate the rootblocks since any rootblock that references -// * the old allocation area will be invalid. -// * -// * TODO: Should be replaced with specific updateExtendedMetaData that will -// * simply reset the metaBitsAddr -// * @throws IOException -// */ -// protected void writeFileSpec() throws IOException { -// -// m_rb = m_fmv.newRootBlockView(// -// !m_rb.isRootBlock0(), // -// m_rb.getOffsetBits(), // -// getNextOffset(), // -// m_rb.getFirstCommitTime(),// -// m_rb.getLastCommitTime(), // -// m_rb.getCommitCounter(), // -// m_rb.getCommitRecordAddr(),// -// m_rb.getCommitRecordIndexAddr(), // -// getMetaStartAddr(),// -// getMetaBitsAddr(), // -// m_rb.getLastCommitTime()// -// ); -// -// m_fmv.getFileMetadata().writeRootBlock(m_rb, ForceEnum.Force); -// -// } - -// float m_vers = 0.0f; -// -// protected void readFileSpec() { -// if (true) { -// throw new Error("Unexpected old format initialisation called"); -// } -// -// try { -// m_raf.seek(0); -// m_curHdrAddr = m_raf.readLong(); -// -// m_fileSize = m_raf.readInt(); -// m_metaStartAddr = m_raf.readInt(); -// -// m_vers = m_raf.readFloat(); -// -// if (m_vers != s_version) { -// String msg = "Incorrect store version : " + m_vers + " expects : " + s_version; -// -// throw new IOException(msg); -// } else { -// m_headerSize = m_raf.readInt(); -// } -// -// } catch (IOException e) { -// throw new StorageTerminalError("Unable to read file spec", e); -// } -// } - public String getVersionString() { return "RWStore " + s_version; } @@ -1696,7 +1631,7 @@ // m_commitCallback.commitComplete(); // } - m_raf.getChannel().force(false); // TODO, check if required! + m_reopener.reopenChannel().force(false); // TODO, check if required! } catch (IOException e) { throw new StorageTerminalError("Unable to commit transaction", e); } finally { @@ -2088,7 +2023,8 @@ if (log.isInfoEnabled()) log.info("Extending file to: " + toAddr); - m_raf.setLength(toAddr); + m_reopener.reopenChannel(); + m_reopener.raf.setLength(toAddr); if (log.isInfoEnabled()) log.info("Extend file done"); } catch (Throwable t) { @@ -2588,7 +2524,8 @@ } /** - * Simple implementation for a {@link RandomAccessFile} to handle the direct backing store. + * Simple implementation for a {@link RandomAccessFile} to handle the direct + * backing store. */ private static class ReopenFileChannel implements IReopenChannel<FileChannel> { @@ -3107,18 +3044,6 @@ * Note: This uses the [opener] to automatically retry the operation * in case concurrent readers are interrupting, causing an * asynchronous close of the backing channel. - * - * @todo Consider using the read lock vs the write lock of the - * extensionLock here. The advantage of the read lock is higher - * concurrency. The advantage of the write lock is that it locks out - * readers when we are writing the root blocks, which could help to - * ensure timely updates of the root blocks even if readers are - * behaving badly (lots of interrupts). - * - * FIXME Modify AbstractInterruptsTestCase to test for correct - * handling of root block writes where concurrent readers cause the - * backing store to be closed asynchronously. This code block SHOULD - * cause the root block write to eventually succeed. */ final Lock lock = m_extensionLock.readLock(); lock.lock(); @@ -3133,13 +3058,6 @@ * to the disk when we change the file size (unless the file * system updates other aspects of file metadata during normal * writes). - * - * @todo make sure the journal has already forced the writes, - * that forcing an empty cache buffer is a NOP, and that we want - * to just force the channel after we write the root blocks - * since writes were already forced on each node in the quorum - * before we wrote the root blocks and the root blocks are - * transmitted using RMI not the write pipeline. */ // sync the disk. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 18:00:50 UTC (rev 3883) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 18:53:49 UTC (rev 3884) @@ -1023,10 +1023,10 @@ Journal store = (Journal) getStore(); - RWStrategy bs = (RWStrategy) store.getBufferStrategy(); + final RWStrategy bs = (RWStrategy) store.getBufferStrategy(); - RWStore rw = bs.getRWStore(); - long realAddr = 0; + final RWStore rw = bs.getRWStore(); +// long realAddr = 0; try { // allocBatch(store, 1, 32, 650, 100000000); allocBatch(store, 1, 32, 650, 5000000); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-04 11:05:00
|
Revision: 3886 http://bigdata.svn.sourceforge.net/bigdata/?rev=3886&view=rev Author: thompsonbry Date: 2010-11-04 11:04:52 +0000 (Thu, 04 Nov 2010) Log Message: ----------- Rationalized life cycle semantics in RWStrategy and RWStore a bit. Adding performance counters to RWStrategy and RWStore (not quite done yet). Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-03 23:05:00 UTC (rev 3885) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-04 11:04:52 UTC (rev 3886) @@ -33,6 +33,7 @@ import org.apache.log4j.Logger; import com.bigdata.counters.CounterSet; +import com.bigdata.journal.WORMStrategy.StoreCounters; import com.bigdata.journal.ha.HAWriteMessage; import com.bigdata.mdi.IResourceMetadata; import com.bigdata.quorum.Quorum; @@ -42,22 +43,30 @@ import com.bigdata.rwstore.RWStore; /** - * The hook that accesses the RWStore to provide read/write services as opposed - * to the WORM characteristics of the DiskOnlyStrategy AddressManager. + * A highly scalable persistent {@link IBufferStrategy} wrapping the + * {@link RWStore} which may be used as the backing store for a {@link Journal}. + * <p> + * The {@link RWStore} manages allocation slots. This can translate into an + * enormous space savings on the disk for large data sets (when compared to the + * WORM) since old revisions of B+Tree nodes and leaves may be recycled + * efficiently. * - * The intent behind this approach is to try to manage the protocol differences - * between the IStore implementation, assumed as a backing service to the CTC - * ObjectManager, and an IBufferStrategy service for a BigData Journal. + * <h2>History</h2> * - * The most fundamental difference is with the root data, with RootBlock - * including both low-level store data - such as metabits info - and higher - * level, journal maintained data. + * The {@link RWStrategy} supports access to historical commit states in + * combination with the history retention policy of the + * {@link ITransactionService}. * + * <h2>Compatibility</h2> + * + * The {@link RWStore} uses a distinct binary layout on the disk based which is + * not directly compatible with the WORM binary storage layer. The WORM and the + * {@link RWStore} uses the same file header and root blocks. However, the + * {@link RWStore} defines some fields in the root blocks which are not used by + * the WORM store such as the metabits info. In addition, some of the root block + * fields defined by the WORM store are not used by the {@link RWStore}. + * * @author Martyn Cutcher - * - * FIXME Review life cycle state changes and refusal of methods when the - * backing store is closed. m_open should probably be moved into RWStore - * which could then expose an isOpen() method to be used by this class. */ public class RWStrategy extends AbstractRawStore implements IBufferStrategy, IHABufferStrategy { @@ -76,11 +85,6 @@ private final UUID m_uuid; /** - * <code>true</code> iff the backing store is open. - */ - private volatile boolean m_open = false; - - /** * The size of the backing file when it was opened by the constructor. */ final private long m_initialExtent; @@ -96,26 +100,24 @@ m_store = new RWStore(fileMetadata, quorum); - m_open = true; - m_initialExtent = fileMetadata.file.length(); } public ByteBuffer readRootBlock(final boolean rootBlock0) { - if (!isOpen()) - throw new IllegalStateException(); - return m_store.readRootBlock(rootBlock0); } + /* + * FIXME This does not handle the read-from-peer HA integration. See + * WORMStrategy#read(). + * + * FIXME This does not update the StoreCounters. + */ public ByteBuffer read(final long addr) { - if (!isOpen()) - throw new IllegalStateException(); - final int rwaddr = decodeAddr(addr); final int sze = decodeSize(addr); @@ -237,15 +239,9 @@ } - /** - * @todo Define and implement support for counters. The pattern for this - * method is to always return a new object so it may be attached to - * various points in hierarchies belonging to the caller. See the - * {@link WORMStrategy} for examples. - */ public CounterSet getCounters() { - return new CounterSet(); + return m_store.getStoreCounters().getCounters(); } @@ -317,21 +313,26 @@ } - /** - * Set close time in rootBlock, and close file - */ + private void assertOpen() { + + if (!m_store.isOpen()) + throw new IllegalStateException(); + + } + public void close() { - if (!m_open) { - throw new IllegalStateException(); - } + + // throw exception if open per the API. + assertOpen(); + m_store.close(); - m_open = false; + } public void deleteResources() { - if (m_open) - throw new IllegalArgumentException(); + if (m_store.isOpen()) + throw new IllegalStateException(); final File file = m_store.getStoreFile(); @@ -339,6 +340,7 @@ if (!file.delete()) { +// throw new RuntimeException("Unable to delete file: " + file); log.warn("Unable to delete file: " + file); } @@ -349,9 +351,10 @@ public void destroy() { + // close w/o exception throw. m_store.close(); - m_open = false; + // delete the backing store. deleteResources(); } @@ -417,7 +420,7 @@ public boolean isOpen() { - return m_open; + return m_store.isOpen(); } @@ -439,7 +442,9 @@ * This implementation returns the amount of utilized storage. */ public long size() { - return m_store.getFileStorage(); + + return m_store.getFileStorage(); + } /* Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-03 23:05:00 UTC (rev 3885) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-04 11:04:52 UTC (rev 3886) @@ -40,6 +40,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -50,6 +51,10 @@ import com.bigdata.btree.ITuple; import com.bigdata.btree.ITupleIterator; import com.bigdata.btree.IndexMetadata; +import com.bigdata.btree.BTree.Counter; +import com.bigdata.counters.CounterSet; +import com.bigdata.counters.Instrument; +import com.bigdata.counters.striped.StripedCounters; import com.bigdata.io.FileChannelUtility; import com.bigdata.io.IReopenChannel; import com.bigdata.io.writecache.BufferedWrite; @@ -66,7 +71,9 @@ import com.bigdata.journal.Options; import com.bigdata.journal.RootBlockUtility; import com.bigdata.journal.RootBlockView; +import com.bigdata.journal.WORMStrategy.StoreCounters; import com.bigdata.quorum.Quorum; +import com.bigdata.rawstore.IRawStore; import com.bigdata.util.ChecksumUtility; /** @@ -351,6 +358,11 @@ private volatile BufferedWrite m_bufferedWrite; + /** + * <code>true</code> iff the backing store is open. + */ + private volatile boolean m_open = true; + class WriteCacheImpl extends WriteCache.FileChannelScatteredWriteCache { public WriteCacheImpl(final ByteBuffer buf, final boolean useChecksum, @@ -364,17 +376,32 @@ } + /* + * FIXME Update counters when writing on the disk. + */ @Override protected boolean writeOnChannel(final ByteBuffer data, final long firstOffsetignored, final Map<Long, RecordMetadata> recordMap, final long nanos) throws InterruptedException, IOException { - +// final long begin = System.nanoTime(); final Lock readLock = m_extensionLock.readLock(); readLock.lock(); try { - return super.writeOnChannel(data, firstOffsetignored, + boolean ret = super.writeOnChannel(data, firstOffsetignored, recordMap, nanos); +// // Update counters. +// final long elapsed = (System.nanoTime() - begin); +// final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() +// .acquire(); +// try { +// c.ndiskWrite += nwrites; +// c.bytesWrittenOnDisk += nbytes; +// c.elapsedDiskWriteNanos += elapsed; +// } finally { +// c.release(); +// } + return ret; } finally { readLock.unlock(); } @@ -428,6 +455,9 @@ m_fd = fileMetadata.file; + // initialize striped performance counters for this store. + this.storeCounters.set(new StoreCounters(10/* batchSize */)); + final IRootBlockView m_rb = fileMetadata.rootBlock; m_commitList = new ArrayList<Allocator>(); @@ -536,7 +566,17 @@ } } + public boolean isOpen() { + return m_open; + } + + private void assertOpen() { + if(!m_open) + throw new IllegalStateException(); + } + synchronized public void close() { + m_open = false; try { if (m_bufferedWrite != null) { m_bufferedWrite.release(); @@ -935,22 +975,26 @@ volatile private int m_frees = 0; volatile private long m_nativeAllocBytes = 0; - /** - * If the buf[] size is greater than the maximum fixed allocation, then the direct read - * will be the blob header record. In this case we should hand over the streaming to a PSInputStream. - * - * FIXME: For now we do not use the PSInputStream but instead process directly - * - * If it is a BlobAllocation, then the BlobAllocation address points to the address of the BlobHeader - * record. - */ + /** + * If the buf[] size is greater than the maximum fixed allocation, then the + * direct read will be the blob header record. In this case we should hand + * over the streaming to a PSInputStream. + * + * FIXME: For now we do not use the PSInputStream but instead process + * directly + * + * If it is a BlobAllocation, then the BlobAllocation address points to the + * address of the BlobHeader record. + */ public void getData(final long addr, final byte buf[]) { getData(addr, buf, 0, buf.length); } public void getData(final long addr, final byte buf[], final int offset, final int length) { - + + assertOpen(); + if (addr == 0) { return; } @@ -1135,32 +1179,41 @@ // } } - /*************************************************************************************** - * this supports the core functionality of a WormStore, other stores should - * return zero, indicating no previous versions available - **/ + /** + * Always returns ZERO (0L). + * <p> + * This is intended to support the core functionality of a WormStore, other + * stores should return zero, indicating no previous versions available + */ public long getPreviousAddress(final long laddr) { - return 0; + + return 0; + } public void free(final long laddr, final int sze) { - free(laddr, sze, null); // call with null AlocationContext + + free(laddr, sze, null/* AlocationContext */); + } - /** - * free - * - * If the address is greater than zero than it is interpreted as a physical address and - * the allocators are searched to find the allocations. Otherwise the address directly encodes - * the allocator index and bit offset, allowing direct access to clear the allocation. - * <p> - * A blob allocator contains the allocator index and offset, so an allocator contains up to - * 245 blob references. - * - * @param sze - */ + /** + * free + * <p> + * If the address is greater than zero than it is interpreted as a physical + * address and the allocators are searched to find the allocations. + * Otherwise the address directly encodes the allocator index and bit + * offset, allowing direct access to clear the allocation. + * <p> + * A blob allocator contains the allocator index and offset, so an allocator + * contains up to 245 blob references. + * + * @param laddr + * @param sze + * @param context + */ public void free(final long laddr, final int sze, final IAllocationContext context) { -// if (true) return; + assertOpen(); final int addr = (int) laddr; switch (addr) { @@ -1368,31 +1421,42 @@ * TODO: Instead of using PSOutputStream, manage allocations written to the * WriteCacheService, building BlobHeader as you go. **/ - public long alloc(final byte buf[], final int size, final IAllocationContext context) { - if (size > (m_maxFixedAlloc-4)) { - if (size > (BLOB_FIXED_ALLOCS * (m_maxFixedAlloc-4))) - throw new IllegalArgumentException("Allocation request beyond maximum BLOB"); - - if (log.isTraceEnabled()) - log.trace("BLOB ALLOC: " + size); + public long alloc(final byte buf[], final int size, + final IAllocationContext context) { - final PSOutputStream psout = PSOutputStream.getNew(this, m_maxFixedAlloc, context); - try { - int i = 0; - final int lsize = size - 512; - while (i < lsize) { - psout.write(buf, i, 512); // add 512 bytes at a time - i += 512; - } - psout.write(buf, i, size - i); + final long begin = System.nanoTime(); + + if (size > (m_maxFixedAlloc - 4)) { + + if (size > (BLOB_FIXED_ALLOCS * (m_maxFixedAlloc - 4))) + throw new IllegalArgumentException( + "Allocation request beyond maximum BLOB"); - return psout.save(); - } catch (IOException e) { - throw new RuntimeException("Closed Store?", e); - } + if (log.isTraceEnabled()) + log.trace("BLOB ALLOC: " + size); - } + final PSOutputStream psout = PSOutputStream.getNew(this, + m_maxFixedAlloc, context); + try { + + int i = 0; + final int lsize = size - 512; + while (i < lsize) { + psout.write(buf, i, 512); // add 512 bytes at a time + i += 512; + } + psout.write(buf, i, size - i); + return psout.save(); + + } catch (IOException e) { + + throw new RuntimeException("Closed Store?", e); + + } + + } + final int newAddr = alloc(size + 4, context); // allow size for checksum final int chk = ChecksumUtility.getCHK().checksum(buf, size); @@ -1403,7 +1467,22 @@ throw new RuntimeException("Closed Store?", e); } - return newAddr; + // Update counters. + final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() + .acquire(); + try { + final int nwrite = size + 4;// size plus checksum. + c.nwrites++; + c.bytesWritten += nwrite; + c.elapsedWriteNanos += (System.nanoTime() - begin); + if (nwrite > c.maxWriteSize) { + c.maxWriteSize = nwrite; + } + } finally { + c.release(); + } + + return newAddr; } // /**************************************************************************** @@ -1471,6 +1550,7 @@ * block. */ public void reset() { + assertOpen(); if (log.isInfoEnabled()) { log.info("RWStore Reset"); } @@ -1565,6 +1645,7 @@ } public void commitChanges(final Journal journal) { + assertOpen(); checkCoreAllocations(); // take allocation lock to prevent other threads allocating during commit @@ -2025,6 +2106,7 @@ m_reopener.reopenChannel(); m_reopener.raf.setLength(toAddr); + storeCounters.get().ntruncate++; if (log.isInfoEnabled()) log.info("Extend file done"); } catch (Throwable t) { @@ -2465,22 +2547,43 @@ log.trace("Returning nextOffset: " + ret + ", for " + m_metaBitsAddr); return ret; - } + } - public void flushWrites(final boolean metadata) throws IOException { - try { - m_writeCache.flush(metadata); - } catch (InterruptedException e) { - throw new ClosedByInterruptException(); - } - } + public void flushWrites(final boolean metadata) throws IOException { + assertOpen(); + + try { + + m_writeCache.flush(metadata); + + // sync the disk. + m_reopener.reopenChannel().force(metadata); + + final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() + .acquire(); + try { + c.nforce++; + } finally { + c.release(); + } + + } catch (InterruptedException e) { + + throw new ClosedByInterruptException(); + + } + + } + public long getTotalAllocations() { return m_allocations; } + public long getTotalFrees() { return m_frees; } + public long getTotalAllocationsSize() { return m_nativeAllocBytes; } @@ -2527,7 +2630,7 @@ * Simple implementation for a {@link RandomAccessFile} to handle the direct * backing store. */ - private static class ReopenFileChannel implements + private class ReopenFileChannel implements IReopenChannel<FileChannel> { final private File file; @@ -2574,9 +2677,15 @@ // open the file. this.raf = new RandomAccessFile(file, mode); - if (log.isInfoEnabled()) - log.info("(Re-)opened file: " + file); - + // Update counters. + final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() + .acquire(); + try { + c.nreopen++; + } finally { + c.release(); + } + return raf.getChannel(); } @@ -2584,16 +2693,16 @@ } /** - * Delegated to from setExtentForLocalStore after expected call from - * HAGlue.replicateAndReceive. - * * If the current file extent is different from the required extent then the - * call is made to move the allocation blocks. + * call is made to {@link #extendFile(int)}. * * @param extent + * The new file extent. */ public void establishExtent(final long extent) { + assertOpen(); + final long currentExtent = convertAddr(m_fileSize); if (extent != currentExtent) { @@ -2864,16 +2973,17 @@ } - /** - * The ContextAllocation object manages a freeList of associated allocators - * and an overall list of allocators. When the context is detached, all - * allocators must be released and any that has available capacity will - * be assigned to the global free lists. - * - * @param context - * The context to be released from all FixedAllocators. - */ + /** + * The ContextAllocation object manages a freeList of associated allocators + * and an overall list of allocators. When the context is detached, all + * allocators must be released and any that has available capacity will be + * assigned to the global free lists. + * + * @param context + * The context to be released from all FixedAllocators. + */ public void detachContext(final IAllocationContext context) { + assertOpen(); m_allocationLock.lock(); try { final ContextAllocation alloc = m_contexts.remove(context); @@ -2897,7 +3007,8 @@ * @author Martyn Cutcher * */ - class ContextAllocation { + static class ContextAllocation { + private final RWStore m_store; private final ArrayList<FixedAllocator> m_freeFixed[]; private final ArrayList<FixedAllocator> m_allFixed; @@ -2908,15 +3019,21 @@ private final ContextAllocation m_parent; private final IAllocationContext m_context; - ContextAllocation(final int fixedBlocks, + ContextAllocation(RWStore store, + final int fixedBlocks, final ContextAllocation parent, final IAllocationContext acontext) { + + m_store = store; m_parent = parent; m_context = acontext; m_freeFixed = new ArrayList[fixedBlocks]; + for (int i = 0; i < m_freeFixed.length; i++) { - m_freeFixed[i] = new ArrayList<FixedAllocator>(); + + m_freeFixed[i] = new ArrayList<FixedAllocator>(); + } m_allFixed = new ArrayList<FixedAllocator>(); @@ -2927,7 +3044,7 @@ void release() { final ArrayList<FixedAllocator> freeFixed[] = m_parent != null ? m_parent.m_freeFixed - : RWStore.this.m_freeFixed; + : m_store.m_freeFixed; final IAllocationContext pcontext = m_parent == null ? null : m_parent.m_context; @@ -2962,7 +3079,7 @@ */ FixedAllocator establishFixedAllocator(final int i) { if (m_parent == null) { - return RWStore.this.establishFreeFixedAllocator(i); + return m_store.establishFreeFixedAllocator(i); } else { return m_parent.establishFixedAllocator(i); } @@ -2985,7 +3102,7 @@ if (ret == null) { - ret = new ContextAllocation(m_freeFixed.length, null, context); + ret = new ContextAllocation(this, m_freeFixed.length, null, context); m_contexts.put(context, ret); @@ -3024,6 +3141,8 @@ checkRootBlock(rootBlock); + assertOpen(); + if (log.isTraceEnabled()) { log.trace("Writing new rootblock with commitCounter: " + rootBlock.getCommitCounter() + ", commitRecordAddr: " @@ -3063,14 +3182,14 @@ // sync the disk. m_reopener.reopenChannel().force(forceOnCommit == ForceEnum.ForceMetadata); -// // Update counters. -// final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() -// .acquire(); -// try { -// c.nwriteRootBlock++; -// } finally { -// c.release(); -// } + // Update counters. + final StoreCounters<?> c = (StoreCounters<?>) storeCounters.get() + .acquire(); + try { + c.nwriteRootBlock++; + } finally { + c.release(); + } } finally { @@ -3091,6 +3210,8 @@ public ByteBuffer readRootBlock(final boolean rootBlock0) { + assertOpen(); + final ByteBuffer tmp = ByteBuffer .allocate(RootBlockView.SIZEOF_ROOT_BLOCK); @@ -3112,4 +3233,523 @@ } + /** + * Striped performance counters for {@link IRawStore} access, including + * operations that read or write through to the underlying media. + * + * @author <a href="mailto:tho...@us...">Bryan + * Thompson</a> + * @param <T> + * + * @todo report elapsed time and average latency for force, reopen, and + * writeRootBlock. + * + * FIXME CAT may be much faster than striped locks (2-3x faster). + */ + static public class StoreCounters<T extends StoreCounters<T>> extends + StripedCounters<T> { + + /** + * #of read requests. + */ + public volatile long nreads; + + /** + * #of read requests that read through to the backing file. + */ + public volatile long ndiskRead; + + /** + * #of bytes read. + */ + public volatile long bytesRead; + + /** + * #of bytes that have been read from the disk. + */ + public volatile long bytesReadFromDisk; + + /** + * Total elapsed time for reads. + */ + public volatile long elapsedReadNanos; + + /** + * Total elapsed time for reading on the disk. + */ + public volatile long elapsedDiskReadNanos; + + /** + * The #of checksum errors while reading on the local disk. + */ + public volatile long checksumErrorCount; + + /** + * #of write requests. + */ + public volatile long nwrites; + + /** + * #of write requests that write through to the backing file. + */ + public volatile long ndiskWrite; + + /** + * The size of the largest record read. + */ + public volatile long maxReadSize; + + /** + * The size of the largest record written. + */ + public volatile long maxWriteSize; + + /** + * #of bytes written. + */ + public volatile long bytesWritten; + + /** + * #of bytes that have been written on the disk. + */ + public volatile long bytesWrittenOnDisk; + + /** + * Total elapsed time for writes. + */ + public volatile long elapsedWriteNanos; + + /** + * Total elapsed time for writing on the disk. + */ + public volatile long elapsedDiskWriteNanos; + + /** + * #of times the data were forced to the disk. + */ + public volatile long nforce; + + /** + * #of times the length of the file was changed (typically, extended). + */ + public volatile long ntruncate; + + /** + * #of times the file has been reopened after it was closed by an + * interrupt. + */ + public volatile long nreopen; + + /** + * #of times one of the root blocks has been written. + */ + public volatile long nwriteRootBlock; + + /** + * {@inheritDoc} + */ + public StoreCounters() { + super(); + } + + /** + * {@inheritDoc} + */ + public StoreCounters(final int batchSize) { + super(batchSize); + } + + /** + * {@inheritDoc} + */ + public StoreCounters(final int nstripes, final int batchSize) { + super(nstripes, batchSize); + } + + @Override + public void add(final T o) { + + super.add(o); + + nreads += o.nreads; + ndiskRead += o.ndiskRead; + bytesRead += o.bytesRead; + bytesReadFromDisk += o.bytesReadFromDisk; + maxReadSize = Math.max(maxReadSize, o.maxReadSize); + elapsedReadNanos += o.elapsedReadNanos; + elapsedDiskReadNanos += o.elapsedDiskReadNanos; + checksumErrorCount += o.checksumErrorCount; + + nwrites += o.nwrites; + ndiskWrite += o.ndiskWrite; + maxWriteSize = Math.max(maxWriteSize, o.maxWriteSize); + bytesWritten += o.bytesWritten; + bytesWrittenOnDisk += o.bytesWrittenOnDisk; + elapsedWriteNanos += o.elapsedWriteNanos; + elapsedDiskWriteNanos += o.elapsedDiskWriteNanos; + + nforce += o.nforce; + ntruncate += o.ntruncate; + nreopen += o.nreopen; + nwriteRootBlock += o.nwriteRootBlock; + + } + + @Override + public T subtract(final T o) { + + // make a copy of the current counters. + final T t = super.subtract(o); + + // subtract out the given counters. + t.nreads -= o.nreads; + t.ndiskRead -= o.ndiskRead; + t.bytesRead -= o.bytesRead; + t.bytesReadFromDisk -= o.bytesReadFromDisk; + t.maxReadSize -= o.maxReadSize; // @todo report max? min? + t.elapsedReadNanos -= o.elapsedReadNanos; + t.elapsedDiskReadNanos -= o.elapsedDiskReadNanos; + t.checksumErrorCount -= o.checksumErrorCount; + + t.nwrites -= o.nwrites; + t.ndiskWrite -= o.ndiskWrite; + t.maxWriteSize -= o.maxWriteSize; // @todo report max? min? + t.bytesWritten -= o.bytesWritten; + t.bytesWrittenOnDisk -= o.bytesWrittenOnDisk; + t.elapsedWriteNanos -= o.elapsedWriteNanos; + t.elapsedDiskWriteNanos -= o.elapsedDiskWriteNanos; + + t.nforce -= o.nforce; + t.ntruncate -= o.ntruncate; + t.nreopen -= o.nreopen; + t.nwriteRootBlock -= o.nwriteRootBlock; + + return t; + + } + + @Override + public void clear() { + + // subtract out the given counters. + nreads = 0; + ndiskRead = 0; + bytesRead = 0; + bytesReadFromDisk = 0; + maxReadSize = 0; + elapsedReadNanos = 0; + elapsedDiskReadNanos = 0; + checksumErrorCount = 0; + + nwrites = 0; + ndiskWrite = 0; + maxWriteSize = 0; + bytesWritten = 0; + bytesWrittenOnDisk = 0; + elapsedWriteNanos = 0; + elapsedDiskWriteNanos = 0; + + nforce = 0; + ntruncate = 0; + nreopen = 0; + nwriteRootBlock = 0; + + } + + @Override + public CounterSet getCounters() { + + final CounterSet root = super.getCounters(); + + // IRawStore API + { + + /* + * reads + */ + + root.addCounter("nreads", new Instrument<Long>() { + public void sample() { + setValue(nreads); + } + }); + + root.addCounter("bytesRead", new Instrument<Long>() { + public void sample() { + setValue(bytesRead); + } + }); + + root.addCounter("readSecs", new Instrument<Double>() { + public void sample() { + final double elapsedReadSecs = (elapsedReadNanos / 1000000000.); + setValue(elapsedReadSecs); + } + }); + + root.addCounter("bytesReadPerSec", new Instrument<Double>() { + public void sample() { + final double readSecs = (elapsedReadNanos / 1000000000.); + final double bytesReadPerSec = (readSecs == 0L ? 0d + : (bytesRead / readSecs)); + setValue(bytesReadPerSec); + } + }); + + root.addCounter("maxReadSize", new Instrument<Long>() { + public void sample() { + setValue(maxReadSize); + } + }); + + root.addCounter("checksumErrorCount", new Instrument<Long>() { + public void sample() { + setValue(checksumErrorCount); + } + }); + + /* + * writes + */ + + root.addCounter("nwrites", new Instrument<Long>() { + public void sample() { + setValue(nwrites); + } + }); + + root.addCounter("bytesWritten", new Instrument<Long>() { + public void sample() { + setValue(bytesWritten); + } + }); + + root.addCounter("writeSecs", new Instrument<Double>() { + public void sample() { + final double writeSecs = (elapsedWriteNanos / 1000000000.); + setValue(writeSecs); + } + }); + + root.addCounter("bytesWrittenPerSec", new Instrument<Double>() { + public void sample() { + final double writeSecs = (elapsedWriteNanos / 1000000000.); + final double bytesWrittenPerSec = (writeSecs == 0L ? 0d + : (bytesWritten / writeSecs)); + setValue(bytesWrittenPerSec); + } + }); + + root.addCounter("maxWriteSize", new Instrument<Long>() { + public void sample() { + setValue(maxWriteSize); + } + }); + + } // IRawStore + + // disk statistics + { + final CounterSet disk = root.makePath("disk"); + + /* + * read + */ + + disk.addCounter("nreads", new Instrument<Long>() { + public void sample() { + setValue(ndiskRead); + } + }); + + disk.addCounter("bytesRead", new Instrument<Long>() { + public void sample() { + setValue(bytesReadFromDisk); + } + }); + + disk.addCounter("bytesPerRead", new Instrument<Double>() { + public void sample() { + final double bytesPerDiskRead = (ndiskRead == 0 ? 0d + : (bytesReadFromDisk / (double) ndiskRead)); + setValue(bytesPerDiskRead); + } + }); + + disk.addCounter("readSecs", new Instrument<Double>() { + public void sample() { + final double diskReadSecs = (elapsedDiskReadNanos / 1000000000.); + setValue(diskReadSecs); + } + }); + + disk.addCounter("bytesReadPerSec", new Instrument<Double>() { + public void sample() { + final double diskReadSecs = (elapsedDiskReadNanos / 1000000000.); + final double bytesReadPerSec = (diskReadSecs == 0L ? 0d + : bytesReadFromDisk / diskReadSecs); + setValue(bytesReadPerSec); + } + }); + + disk.addCounter("secsPerRead", new Instrument<Double>() { + public void sample() { + final double diskReadSecs = (elapsedDiskReadNanos / 1000000000.); + final double readLatency = (diskReadSecs == 0 ? 0d + : diskReadSecs / ndiskRead); + setValue(readLatency); + } + }); + + /* + * write + */ + + disk.addCounter("nwrites", new Instrument<Long>() { + public void sample() { + setValue(ndiskWrite); + } + }); + + disk.addCounter("bytesWritten", new Instrument<Long>() { + public void sample() { + setValue(bytesWrittenOnDisk); + } + }); + + disk.addCounter("bytesPerWrite", new Instrument<Double>() { + public void sample() { + final double bytesPerDiskWrite = (ndiskWrite == 0 ? 0d + : (bytesWrittenOnDisk / (double) ndiskWrite)); + setValue(bytesPerDiskWrite); + } + }); + + disk.addCounter("writeSecs", new Instrument<Double>() { + public void sample() { + final double diskWriteSecs = (elapsedDiskWriteNanos / 1000000000.); + setValue(diskWriteSecs); + } + }); + + disk.addCounter("bytesWrittenPerSec", new Instrument<Double>() { + public void sample() { + final double diskWriteSecs = (elapsedDiskWriteNanos / 1000000000.); + final double bytesWrittenPerSec = (diskWriteSecs == 0L ? 0d + : bytesWrittenOnDisk / diskWriteSecs); + setValue(bytesWrittenPerSec); + } + }); + + disk.addCounter("secsPerWrite", new Instrument<Double>() { + public void sample() { + final double diskWriteSecs = (elapsedDiskWriteNanos / 1000000000.); + final double writeLatency = (diskWriteSecs == 0 ? 0d + : diskWriteSecs / ndiskWrite); + setValue(writeLatency); + } + }); + + /* + * other + */ + + disk.addCounter("nforce", new Instrument<Long>() { + public void sample() { + setValue(nforce); + } + }); + + disk.addCounter("nextend", new Instrument<Long>() { + public void sample() { + setValue(ntruncate); + } + }); + + disk.addCounter("nreopen", new Instrument<Long>() { + public void sample() { + setValue(nreopen); + } + }); + + disk.addCounter("rootBlockWrites", new Instrument<Long>() { + public void sample() { + setValue(nwriteRootBlock); + } + }); + + } // disk + + return root; + + } // getCounters() + + } // class StoreCounters + + /** + * Striped performance counters for this class. + */ + private final AtomicReference<StoreCounters> storeCounters = new AtomicReference<StoreCounters>(); + + /** + * Returns the striped performance counters for the store. + */ + public StoreCounters<?> getStoreCounters() { + + return storeCounters.get(); + + } + + /** + * Replaces the {@link StoreCounters} object. + * + * @param storeCounters + * The new {@link Counter}s. + * + * @throws IllegalArgumentException + * if the argument is <code>null</code>. + */ + public void setStoreCounters(final StoreCounters<?> storeCounters) { + + if (storeCounters == null) + throw new IllegalArgumentException(); + + this.storeCounters.set(storeCounters); + + } + + /** + * Return interesting information about the write cache and file operations. + */ + public CounterSet getCounters() { + + final CounterSet root = new CounterSet(); + +// root.addCounter("nextOffset", new Instrument<Long>() { +// public void sample() { +// setValue(nextOffset.get()); +// } +// }); + + root.addCounter("extent", new Instrument<Long>() { + public void sample() { + setValue(getStoreFile().length()); + } + }); + + // attach the most recently updated values from the striped counters. + root.attach(storeCounters.get().getCounters()); + + if (m_writeCache != null) { + + final CounterSet tmp = root.makePath("writeCache"); + + tmp.attach(m_writeCache.getCounters()); + + } + + return root; + + } + } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-03 23:05:00 UTC (rev 3885) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-04 11:04:52 UTC (rev 3886) @@ -138,6 +138,8 @@ */ public void test_create_disk01() throws IOException { + File file = null; + final Properties properties = getProperties(); final Journal journal = new Journal(properties); @@ -161,12 +163,17 @@ assertEquals(Options.BUFFER_MODE, BufferMode.DiskRW, bufferStrategy .getBufferMode()); + file = journal.getFile(); + } finally { journal.destroy(); } + if(file != null && file.exists()) + fail("Did not delete the backing file: "+file); + } /** This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-04 16:30:20
|
Revision: 3894 http://bigdata.svn.sourceforge.net/bigdata/?rev=3894&view=rev Author: thompsonbry Date: 2010-11-04 16:30:14 +0000 (Thu, 04 Nov 2010) Log Message: ----------- Moved some Options into RWStore.Options. The metaBitsSize option needs to become persistent. Martyn is going to handle that one. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java 2010-11-04 15:23:28 UTC (rev 3893) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Options.java 2010-11-04 16:30:14 UTC (rev 3894) @@ -41,7 +41,6 @@ import com.bigdata.rawstore.WormAddressManager; import com.bigdata.resources.ResourceManager; import com.bigdata.resources.StoreManager.ManagedJournal; -import com.bigdata.rwstore.RWStore; /** * Options for the {@link Journal}. Options are specified as property values to @@ -484,19 +483,6 @@ String TMP_DIR = AbstractJournal.class.getName()+".tmpDir"; /** - * The following option provides the Allocation block sizes for the - * RWStore. The values defined are multiplied by 64 to provide the - * actual allocations. The list of allocaitons should be ',' delimited - * and in increasing order. eg: - * "1,2,4,8,116,32,64" defines allocaitons from 64 to 4K in size. - * The default allocations are: - * "1,2,3,5,8,12,16,32,48,64,128,192,320,512,832,1344,2176,3520" providing - * blocks up to 220K aligned on 4K boundaries as soon as possible to - * optimise IO - particularly relevant for SSDs. - */ - String RW_ALLOCATIONS = RWStore.class.getName()+".allocSizes"; - - /** * When <code>true</code> (default {@value #DEFAULT_FILE_LOCK_ENABLED}) a * {@link FileLock} will be sought for the journal by default. When * <code>false</code> only an advisory lock will be sought. Note that Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-04 15:23:28 UTC (rev 3893) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-11-04 16:30:14 UTC (rev 3894) @@ -69,6 +69,8 @@ * the WORM store such as the metabits info. In addition, some of the root block * fields defined by the WORM store are not used by the {@link RWStore}. * + * @see RWStore.Options + * * @author Martyn Cutcher */ public class RWStrategy extends AbstractRawStore implements IBufferStrategy, IHABufferStrategy { Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-04 15:23:28 UTC (rev 3893) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-04 16:30:14 UTC (rev 3894) @@ -70,7 +70,6 @@ import com.bigdata.journal.IRootBlockView; import com.bigdata.journal.Journal; import com.bigdata.journal.JournalTransactionService; -import com.bigdata.journal.Options; import com.bigdata.journal.RootBlockUtility; import com.bigdata.journal.RootBlockView; import com.bigdata.journal.ha.HAWriteMessage; @@ -199,23 +198,70 @@ private static final transient Logger log = Logger.getLogger(RWStore.class); /** - * The sizes of the slots managed by a {@link FixedAllocator} are 64 times - * the values in this array. This array is written into the store so - * changing the values does not break older stores. This array is - * configurable using {@link com.bigdata.journal.Options#RW_ALLOCATIONS}. - * <p> - * Note: It is good to have 4k and 8k boundaries for better efficiency on - * SSD. A 1K boundary is expressed as <code>16</code> in the allocation - * sizes, so a 4K boundary is expressed as <code>64</code>. The default - * series of allocation sizes is based on the Fibonacci sequence, but is - * pegged to the closest 4K boundary for values larger than 4k. - * - * @see #m_allocSizes + * Options understood by the {@link RWStore}. */ - private static final int[] DEFAULT_ALLOC_SIZES = { 1, 2, 3, 5, 8, 12, 16, 32, 48, 64, 128, 192, 320, 512, 832, 1344, 2176, 3520 }; - // private static final int[] DEFAULT_ALLOC_SIZES = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181 }; - // private static final int[] ALLOC_SIZES = { 1, 2, 4, 8, 16, 32, 64, 128 }; + public interface Options { + /** + * Option defines the Allocation block sizes for the RWStore. The values + * defined are multiplied by 64 to provide the actual allocations. The + * list of allocations should be ',' delimited and in increasing order. + * For example, + * + * <pre> + * "1,2,4,8,116,32,64" + * </pre> + * + * defines allocations from 64 to 4K in size. The default allocations + * are: + * + * <pre> + * "1,2,3,5,8,12,16,32,48,64,128,192,320,512,832,1344,2176,3520" + * </pre> + * + * providing blocks up to 220K aligned on 4K boundaries as soon as + * possible to optimize IO - particularly relevant for SSDs. + * + * @see #DEFAULT_ALLOCATION_SIZES + */ + String ALLOCATION_SIZES = RWStore.class.getName() + ".allocationSizes"; + + /** + * The sizes of the slots managed by a {@link FixedAllocator} are 64 times + * the values in this array. This array is written into the store so + * changing the values does not break older stores. This array is + * configurable using {@link com.bigdata.journal.Options#ALLOCATION_SIZES}. + * <p> + * Note: It is good to have 4k and 8k boundaries for better efficiency on + * SSD. A 1K boundary is expressed as <code>16</code> in the allocation + * sizes, so a 4K boundary is expressed as <code>64</code>. The default + * series of allocation sizes is based on the Fibonacci sequence, but is + * pegged to the closest 4K boundary for values larger than 4k. + */ + String DEFAULT_ALLOCATION_SIZES = "1, 2, 3, 5, 8, 12, 16, 32, 48, 64, 128, 192, 320, 512, 832, 1344, 2176, 3520"; + // private static final int[] DEFAULT_ALLOC_SIZES = { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181 }; + // private static final int[] ALLOC_SIZES = { 1, 2, 4, 8, 16, 32, 64, 128 }; + + /** + * Option defines the initial size of the meta bits region and effects + * how rapidly this region will grow (default + * {@value #DEFAULT_META_BITS_SIZE}). + * <p> + * Note: A value of <code>9</code> may be used to stress the logic which + * is responsible for the growth in the meta bits region. + */ + String META_BITS_SIZE = RWStore.class.getName() + ".metaBitsSize"; + + String DEFAULT_META_BITS_SIZE = "9"; + + } + + /* + * Error messages. + */ + + private static final String ERR_WRITE_CACHE_CREATE = "Unable to create write cache service"; + /** * The fixed size of any allocator on the disk in bytes. The #of allocations * managed by an allocator is this value times 8 because each slot uses one @@ -252,8 +298,12 @@ // private boolean m_committing; /** - * FIXME This is initially true and is never set to false. Should this all - * go away? + * When <code>true</code> the allocations will not actually be recycled + * until after a store restart. When <code>false</code>, the allocations are + * recycled once they satisfy the history retention requirement. + * + * FIXME Should this go away or be raised as an option for unlimited + * retention until restart? */ private boolean m_preserveSession = false; // private boolean m_readOnly; @@ -285,7 +335,7 @@ /** * The actual allocation sizes as read from the store. * - * @see #DEFAULT_ALLOC_SIZES + * @see #DEFAULT_ALLOCATION_SIZES */ private int[] m_allocSizes; @@ -410,8 +460,6 @@ }; - volatile private int m_metaBitsAddr; - /** * The ALLOC_SIZES must be initialized from either the file or the * properties associated with the fileMetadataView @@ -427,8 +475,16 @@ if (fileMetadata == null) throw new IllegalArgumentException(); + + cDefaultMetaBitsSize = Integer.valueOf(fileMetadata.getProperty( + Options.META_BITS_SIZE, + Options.DEFAULT_META_BITS_SIZE)); + + if (cDefaultMetaBitsSize < 9) + throw new IllegalArgumentException(Options.META_BITS_SIZE + + " : Must be GTE 9"); - m_metaBitsSize = cDefaultMetaBitsSize; + m_metaBitsSize = cDefaultMetaBitsSize; m_metaBits = new int[m_metaBitsSize]; @@ -474,6 +530,7 @@ m_writeCache = new RWWriteCacheService(buffers, m_fd.length(), m_reopener, m_quorum) { + @SuppressWarnings("unchecked") public WriteCache newWriteCache(final ByteBuffer buf, final boolean useChecksum, final boolean bufferHasData, @@ -485,11 +542,10 @@ } }; } catch (InterruptedException e) { - throw new IllegalStateException("Unable to create write cache service", e); + throw new IllegalStateException(ERR_WRITE_CACHE_CREATE, e); } catch (IOException e) { - throw new IllegalStateException("Unable to create write cache service", e); - } - + throw new IllegalStateException(ERR_WRITE_CACHE_CREATE, e); + } try { if (m_rb.getNextOffset() == 0) { // if zero then new file @@ -517,26 +573,25 @@ } } - private void setAllocations(final FileMetadata fileMetadata) throws IOException { + private void setAllocations(final FileMetadata fileMetadata) + throws IOException { + final String buckets = fileMetadata.getProperty( - Options.RW_ALLOCATIONS, null/* default */); - if (buckets == null) { - m_allocSizes = DEFAULT_ALLOC_SIZES; - } else { - final String[] specs = buckets.split(","); - m_allocSizes = new int[specs.length]; - int prevSize = 0; - for (int i = 0; i < specs.length; i++) { - final int nxtSize = Integer.parseInt(specs[i]); - if (nxtSize <= prevSize) - throw new IllegalArgumentException("Invalid AllocSizes property"); - m_allocSizes[i] = nxtSize; - prevSize = nxtSize; - } - } + Options.ALLOCATION_SIZES, Options.DEFAULT_ALLOCATION_SIZES); + final String[] specs = buckets.split("\\s*,\\s*"); + m_allocSizes = new int[specs.length]; + int prevSize = 0; + for (int i = 0; i < specs.length; i++) { + final int nxtSize = Integer.parseInt(specs[i]); + if (nxtSize <= prevSize) + throw new IllegalArgumentException( + "Invalid AllocSizes property"); + m_allocSizes[i] = nxtSize; + prevSize = nxtSize; + } } - private void defaultInit() throws IOException { + private void defaultInit() throws IOException { final int numFixed = m_allocSizes.length; m_freeFixed = new ArrayList[numFixed]; @@ -621,12 +676,6 @@ log.trace("m_allocation: " + nxtalloc + ", m_metaBitsAddr: " + metaBitsAddr + ", m_commitCounter: " + commitCounter); -// /** -// * Ensure rootblock is in sync with external request -// * -// * FIXME No side-effect please. -// */ -// m_rb = rbv; } /** @@ -1829,7 +1878,7 @@ * Note: This adds one to the lastDeferredReleaseTime to give * exclusive lower bound semantics. */ - freeDeferrals(journal, m_lastDeferredReleaseTime+1, + freeDeferrals(journal, m_lastDeferredReleaseTime + 1, latestReleasableTime); } @@ -1867,12 +1916,22 @@ // private int m_headerSize = 2048; - // Meta Allocator - private static int cDefaultMetaBitsSize = 9; // DEBUG FIX ME + /* + * Meta Allocator + */ + + /** + * @see Options#META_BITS_SIZE + */ + private final int cDefaultMetaBitsSize; + /** + * @see Options#META_BITS_SIZE + */ + volatile private int m_metaBitsSize; private int m_metaBits[]; - volatile private int m_metaBitsSize = cDefaultMetaBitsSize; private int m_metaTransientBits[]; // volatile private int m_metaStartAddr; + private volatile int m_metaBitsAddr; volatile private boolean m_recentAlloc = false; @@ -1985,11 +2044,12 @@ return bit; } - private int fndMetabit() { - final int blocks = m_metaBits.length/9; - for (int b = 0; b < blocks; b++) { - final int ret = fndBit(m_metaTransientBits, (b*9)+1, 8); - if (ret != -1) { + private int fndMetabit() { + final int blocks = m_metaBits.length / cDefaultMetaBitsSize; + for (int b = 0; b < blocks; b++) { + final int ret = fndBit(m_metaTransientBits, + (b * cDefaultMetaBitsSize) + 1, 8); + if (ret != -1) { return ret; } } @@ -3082,7 +3142,8 @@ private final ContextAllocation m_parent; private final IAllocationContext m_context; - ContextAllocation(RWStore store, + @SuppressWarnings("unchecked") + ContextAllocation(final RWStore store, final int fixedBlocks, final ContextAllocation parent, final IAllocationContext acontext) { @@ -3760,6 +3821,7 @@ /** * Striped performance counters for this class. */ + @SuppressWarnings("unchecked") private final AtomicReference<StoreCounters> storeCounters = new AtomicReference<StoreCounters>(); /** Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-04 15:23:28 UTC (rev 3893) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-04 16:30:14 UTC (rev 3894) @@ -246,7 +246,7 @@ properties.setProperty(Options.CREATE_TEMP_FILE, "true"); // properties.setProperty(Options.FILE, "/Volumes/SSDData/TestRW/tmp.rw"); - properties.setProperty(Options.RW_ALLOCATIONS, "1,2,3,5,8,12,16,32,48,64,128,192,320,512,832,1344,2176,3520"); +// properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32,48,64,128,192,320,512,832,1344,2176,3520"); // properties.setProperty(Options.RW_ALLOCATIONS, "1,2,3,5,8,12,16,32,48,64"); properties.setProperty(Options.DELETE_ON_EXIT, "true"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-11-12 15:48:17
|
Revision: 3940 http://bigdata.svn.sourceforge.net/bigdata/?rev=3940&view=rev Author: martyncutcher Date: 2010-11-12 15:48:11 +0000 (Fri, 12 Nov 2010) Log Message: ----------- BlobAllocatorless blob implementation Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java 2010-11-12 00:58:16 UTC (rev 3939) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java 2010-11-12 15:48:11 UTC (rev 3940) @@ -24,10 +24,13 @@ package com.bigdata.rwstore; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import org.apache.log4j.Logger; @@ -140,7 +143,7 @@ * PSOutputStream impl. */ - private int[] m_blobHeader = null; + private ArrayList<Integer> m_blobHeader = null; private byte[] m_buf = null; private boolean m_isSaved = false; // private long m_headAddr = 0; @@ -176,11 +179,8 @@ m_blobThreshold = maxAlloc-4; // allow for checksum - final int maxHdrSize = RWStore.BLOB_FIXED_ALLOCS * 4; - final int bufSize = m_blobThreshold > maxHdrSize ? m_blobThreshold : maxHdrSize; - - if (m_buf == null || m_buf.length != bufSize) - m_buf = new byte[bufSize]; + if (m_buf == null || m_buf.length != m_blobThreshold) + m_buf = new byte[m_blobThreshold]; reset(); } @@ -218,12 +218,16 @@ if (m_count == m_blobThreshold && !m_writingHdr) { if (m_blobHeader == null) { - m_blobHeader = new int[RWStore.BLOB_FIXED_ALLOCS]; // max 16K - m_blobHdrIdx = 0; + int hdrSize = m_blobThreshold/4; + if (hdrSize > RWStore.BLOB_FIXED_ALLOCS) + hdrSize = RWStore.BLOB_FIXED_ALLOCS; + m_blobHeader = new ArrayList<Integer>(); // only support header + // m_blobHdrIdx = 0; } final int curAddr = (int) m_store.alloc(m_buf, m_count, m_context); - m_blobHeader[m_blobHdrIdx++] = curAddr; + // m_blobHeader[m_blobHdrIdx++] = curAddr; + m_blobHeader.add(curAddr); m_count = 0; } @@ -324,28 +328,40 @@ if (m_blobHeader != null) { try { m_writingHdr = true; // ensure that header CAN be a BLOB - m_blobHeader[m_blobHdrIdx++] = addr; + // m_blobHeader[m_blobHdrIdx++] = addr; + m_blobHeader.add(addr); final int precount = m_count; m_count = 0; try { - writeInt(m_blobHdrIdx); - for (int i = 0; i < m_blobHdrIdx; i++) { - writeInt(m_blobHeader[i]); +// writeInt(m_blobHdrIdx); +// for (int i = 0; i < m_blobHdrIdx; i++) { +// writeInt(m_blobHeader[i]); +// } + int hdrBufSize = 4*(m_blobHeader.size() + 1); + ByteArrayOutputStream hdrbuf = new ByteArrayOutputStream(hdrBufSize); + DataOutputStream hdrout = new DataOutputStream(hdrbuf); + hdrout.writeInt(m_blobHeader.size()); + for (int i = 0; i < m_blobHeader.size(); i++) { + hdrout.writeInt(m_blobHeader.get(i)); } - addr = (int) m_store.alloc(m_buf, m_count, m_context); + hdrout.flush(); + + byte[] outbuf = hdrbuf.toByteArray(); + addr = (int) m_store.alloc(outbuf, hdrBufSize, m_context); - if (m_blobHdrIdx != ((m_blobThreshold - 1 + m_bytesWritten - m_count) / m_blobThreshold)) { - throw new IllegalStateException( - "PSOutputStream.save at : " + addr - + ", bytes: " + m_bytesWritten - + ", blocks: " + m_blobHdrIdx - + ", last alloc: " + precount); - } +// if (m_blobHdrIdx != ((m_blobThreshold - 1 + m_bytesWritten - m_count) / m_blobThreshold)) { +// throw new IllegalStateException( +// "PSOutputStream.save at : " + addr +// + ", bytes: " + m_bytesWritten +// + ", blocks: " + m_blobHdrIdx +// + ", last alloc: " + precount); +// } if (log.isDebugEnabled()) log.debug("Writing BlobHdrIdx with " + m_blobHdrIdx + " allocations"); - addr = m_store.registerBlob(addr); // returns handle + // DO NOT USE BLOB ALLOCATOR + // addr = m_store.registerBlob(addr); // returns handle } catch (IOException e) { e.printStackTrace(); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-12 00:58:16 UTC (rev 3939) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-12 15:48:11 UTC (rev 3940) @@ -281,6 +281,8 @@ static final int ALLOCATION_SCALEUP = 16; // multiplier to convert allocations based on minimum allocation of 32k static private final int META_ALLOCATION = 8; // 8 * 32K is size of meta Allocation + // Maximum fixed allocs in a BLOB, but do restrict to size that will fit within a single fixed allocation + // Ignored static final int BLOB_FIXED_ALLOCS = 2048; // private ICommitCallback m_commitCallback; // @@ -578,11 +580,14 @@ } final int maxBlockLessChk = m_maxFixedAlloc-4; - // set this at blob header references max 4096 fixed allocs - // meaning that header may itself be a blob if max fixed is - // less than 16K - m_maxBlobAllocSize = (BLOB_FIXED_ALLOCS * maxBlockLessChk); + // ensure that BLOB header cannot itself be a BLOB +// int blobFixedAlocs = maxBlockLessChk/4; +// if (blobFixedAlocs > RWStore.BLOB_FIXED_ALLOCS) +// blobFixedAlocs = RWStore.BLOB_FIXED_ALLOCS; +// m_maxBlobAllocSize = ((maxBlockLessChk/4) * maxBlockLessChk); + m_maxBlobAllocSize = Integer.MAX_VALUE; + assert m_maxFixedAlloc > 0; m_deferredFreeOut = PSOutputStream.getNew(this, m_maxFixedAlloc, null); @@ -754,8 +759,9 @@ final DataInputStream strBuf = new DataInputStream(new ByteArrayInputStream(buf)); + // Can handle minor store version incompatibility final int storeVersion = strBuf.readInt(); - if (storeVersion != cVersion) { + if ((storeVersion & 0xFF00) != (cVersion & 0xFF00)) { throw new IllegalStateException("Incompatible RWStore header version"); } m_lastDeferredReleaseTime = strBuf.readLong(); @@ -1105,13 +1111,14 @@ } } - final Allocator na = getBlock((int) addr); - if (! (na instanceof BlobAllocator)) { - throw new IllegalStateException("Invalid Allocator index"); - } - final BlobAllocator ba = (BlobAllocator) na; - final int hdraddr = ba.getBlobHdrAddress(getOffset((int) addr)); - getData(hdraddr, hdrbuf); // read in header - could itself be a blob! +// final Allocator na = getBlock((int) addr); +// if (! (na instanceof BlobAllocator)) { +// throw new IllegalStateException("Invalid Allocator index"); +// } +// final BlobAllocator ba = (BlobAllocator) na; +// final int hdraddr = ba.getBlobHdrAddress(getOffset((int) addr)); +// getData(hdraddr, hdrbuf); // read in header - could itself be a blob! + getData(addr, hdrbuf); // fine but MUST NOT allow header to be a BLOB! final DataInputStream hdrstr = new DataInputStream(new ByteArrayInputStream(hdrbuf)); final int rhdrs = hdrstr.readInt(); if (rhdrs != nblocks) { @@ -1369,23 +1376,27 @@ } m_allocationLock.lock(); try { - final Allocator alloc = getBlockByAddress(addr); - /* - * There are a few conditions here. If the context owns the - * allocator and the allocation was made by this context then - * it can be freed immediately. - * The problem comes when the context is null and the allocator - * is NOT owned, BUT there are active AllocationContexts, in this - * situation, the free must ALWAYS be deferred. - */ - final boolean alwaysDefer = context == null && m_contexts.size() > 0; - if (alwaysDefer) - if (log.isDebugEnabled()) - log.debug("Should defer " + physicalAddress(addr)); - if (/*alwaysDefer ||*/ !alloc.canImmediatelyFree(addr, sze, context)) { - deferFree(addr, sze); + if (sze > m_maxFixedAlloc) { + freeBlob(addr, sze, context); } else { - immediateFree(addr, sze); + final Allocator alloc = getBlockByAddress(addr); + /* + * There are a few conditions here. If the context owns the + * allocator and the allocation was made by this context then + * it can be freed immediately. + * The problem comes when the context is null and the allocator + * is NOT owned, BUT there are active AllocationContexts, in this + * situation, the free must ALWAYS be deferred. + */ + final boolean alwaysDefer = context == null && m_contexts.size() > 0; + if (alwaysDefer) + if (log.isDebugEnabled()) + log.debug("Should defer " + physicalAddress(addr)); + if (/*alwaysDefer ||*/ !alloc.canImmediatelyFree(addr, sze, context)) { + deferFree(addr, sze); + } else { + immediateFree(addr, sze); + } } } finally { m_allocationLock.unlock(); @@ -1393,7 +1404,34 @@ } -// private long immediateFreeCount = 0; + private boolean freeBlob(final int hdr_addr, final int sze, final IAllocationContext context) { + if (sze < (m_maxFixedAlloc-4)) + throw new IllegalArgumentException("Unexpected address size"); + + final int alloc = m_maxFixedAlloc-4; + final int blcks = (alloc - 1 + sze)/alloc; + + // read in header block, then free each reference + final byte[] hdr = new byte[(blcks+1) * 4 + 4]; // add space for checksum + getData(hdr_addr, hdr); + + final DataInputStream instr = new DataInputStream( + new ByteArrayInputStream(hdr, 0, hdr.length-4) ); + try { + final int allocs = instr.readInt(); + for (int i = 0; i < allocs; i++) { + final int nxt = instr.readInt(); + free(nxt, m_maxFixedAlloc); + } + free(hdr_addr, hdr.length); + + return true; + } catch (IOException ioe) { + throw new RuntimeException(ioe); + } + } + + // private long immediateFreeCount = 0; private void immediateFree(final int addr, final int sze) { switch (addr) { @@ -1573,9 +1611,9 @@ if (size > (m_maxFixedAlloc - 4)) { - if (size > (BLOB_FIXED_ALLOCS * (m_maxFixedAlloc - 4))) + if (size > getMaxBlobSize()) throw new IllegalArgumentException( - "Allocation request beyond maximum BLOB"); + "Allocation request beyond maximum BLOB of " + getMaxBlobSize()); if (log.isTraceEnabled()) log.trace("BLOB ALLOC: " + size); @@ -1585,8 +1623,8 @@ try { int i = 0; - final int lsize = size - 512; - while (i < lsize) { + final int blocks = size/512; + for (int b = 0; b < blocks; b++) { psout.write(buf, i, 512); // add 512 bytes at a time i += 512; } @@ -1984,8 +2022,14 @@ * Use BCD-style numbering so * 0x0200 == 2.00 * 0x0320 == 3.20 + * + * The minor byte values should maintain binary compatibility, with + * major bytes + * Versions + * 0x0300 - extended header to include reserved ints + * 0x0400 - removed explicit BlobAllocators */ - final private int cVersion = 0x0300; + final private int cVersion = 0x0400; /** * MetaBits Header @@ -2419,12 +2463,10 @@ * number of filled slots | store used */ public void showAllocators(final StringBuilder str) { - final AllocationStats[] stats = new AllocationStats[m_allocSizes.length+1]; - for (int i = 0; i < stats.length-1; i++) { + final AllocationStats[] stats = new AllocationStats[m_allocSizes.length]; + for (int i = 0; i < stats.length; i++) { stats[i] = new AllocationStats(m_allocSizes[i]*64); } - // for BLOBs - stats[stats.length-1] = new AllocationStats(0); final Iterator<Allocator> allocs = m_allocs.iterator(); while (allocs.hasNext()) { @@ -2456,7 +2498,7 @@ tfilled += filled; tfilledSlots += stats[i].m_filledSlots; } - for (int i = 0; i < stats.length-1; i++) { + for (int i = 0; i < stats.length; i++) { final long reserved = stats[i].m_reservedSlots * stats[i].m_blockSize; final long filled = stats[i].m_filledSlots * stats[i].m_blockSize; str.append(padRight("" + stats[i].m_blockSize, 10)); @@ -2466,9 +2508,6 @@ str.append(padLeft("" + (treserved==0?0:(reserved * 100 / treserved)) + "%", 8)); str.append("\n"); } - // lastly some BLOB stats - only interested in used/reserved slots - str.append(padRight("BLOB", 10)); - str.append(padLeft("" + stats[stats.length-1].m_filledSlots, 12) + padLeft("" + stats[stats.length-1].m_reservedSlots, 12)); str.append("\n"); str.append(padRight("Totals", 10)); @@ -3405,6 +3444,11 @@ int ret = m_minFixedAlloc; while (data_len > ret) { i++; + // If we write directly to the writeCache then the data_len + // may be larger than largest slot + if (i == m_allocSizes.length) + return data_len; + ret = 64 * m_allocSizes[i]; } @@ -4059,7 +4103,7 @@ } public int getMaxBlobSize() { - return this.m_maxBlobAllocSize-4; + return m_maxBlobAllocSize-4; // allow for checksum } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-12 00:58:16 UTC (rev 3939) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-12 15:48:11 UTC (rev 3940) @@ -126,6 +126,15 @@ properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); + // number of bits in FixedAllocators + properties.setProperty(com.bigdata.rwstore.RWStore.Options.DEFAULT_FREE_BITS_THRESHOLD, "1000"); + + // Size of META_BITS_BLOCKS + properties.setProperty(com.bigdata.rwstore.RWStore.Options.DEFAULT_META_BITS_SIZE, "9"); + + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32"); // 2K max + properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16"); // 1K + return properties; } @@ -238,6 +247,8 @@ } public Properties getProperties() { + + System.out.println("TestRWJournal:getProperties"); final Properties properties = super.getProperties(); @@ -254,10 +265,26 @@ properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); + // number of bits in FixedAllocators + properties.setProperty(RWStore.Options.FREE_BITS_THRESHOLD, "50"); + + // Size of META_BITS_BLOCKS + properties.setProperty(RWStore.Options.META_BITS_SIZE, "9"); + + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32,48,64,128"); // 8K - max blob = 2K * 8K = 16M + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32,48,64,128"); // 2K max + properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16"); // 2K max + return properties; } + protected IRawStore getStore() { + + return new Journal(getProperties()); + + } + // /** // * Test that allocate() pre-extends the store when a record is allocated // * which would overflow the current user extent. @@ -758,10 +785,10 @@ int endBlob = 1024 * 1256; int[] faddrs = allocBatchBuffer(rw, 100, startBlob, endBlob); - System.out.println("Final allocation: " + rw.physicalAddress(faddrs[99]) - + ", allocations: " + (rw.getTotalAllocations() - numAllocs) - + ", allocated bytes: " + (rw.getTotalAllocationsSize() - startAllocations)); - } finally { + final StringBuilder str = new StringBuilder(); + rw.showAllocators(str); + System.out.println(str); + } finally { store.destroy(); @@ -776,17 +803,17 @@ final Journal store = (Journal) getStore(); try { + final RWStrategy bs = (RWStrategy) store + .getBufferStrategy(); - byte[] buf = new byte[1024 * 2048]; // 2Mb buffer of random data + final RWStore rw = bs.getRWStore(); + + + byte[] buf = new byte[2 * 1024 * 1024]; // 5Mb buffer of random data r.nextBytes(buf); ByteBuffer bb = ByteBuffer.wrap(buf); - RWStrategy bs = (RWStrategy) store - .getBufferStrategy(); - - RWStore rw = bs.getRWStore(); - long faddr = bs.write(bb); // rw.alloc(buf, buf.length); log.info("Blob Allocation at " + rw.convertFromAddr(faddr)); @@ -842,6 +869,12 @@ assertEquals(bb, rdBuf); + // now delete the memory + bs.delete(faddr); // immediateFree! + + faddr = bs.write(bb); // rw.alloc(buf, buf.length); + bb.position(0); + System.out.println("Now commit to disk"); store.commit(); @@ -862,12 +895,12 @@ rw.checkDeferredFrees(true, store); try { - rdBuf = bs.read(faddr); // should fail with illegal state + rdBuf = bs.read(faddr); // should fail with illegal argument throw new RuntimeException("Fail"); } catch (Exception ise) { - assertTrue("Expected IllegalStateException reading from " + (faddr >> 32) + " instead got: " + ise, ise instanceof IllegalStateException); + assertTrue("Expected IllegalArgumentException reading from " + (faddr >> 32) + " instead got: " + ise, ise instanceof IllegalArgumentException); } - + } finally { store.destroy(); @@ -1038,9 +1071,9 @@ // allocBatch(store, 1, 32, 650, 100000000); allocBatch(store, 1, 32, 650, 50000); store.commit(); - System.out.println("Final allocations: " + rw.getTotalAllocations() - + ", allocated bytes: " + rw.getTotalAllocationsSize() + ", file length: " - + rw.getStoreFile().length()); + final StringBuilder str = new StringBuilder(); + rw.showAllocators(str); + System.out.println(str); store.close(); System.out.println("Re-open Journal"); store = (Journal) getStore(); @@ -1065,7 +1098,7 @@ long realAddr = 0; try { // allocBatch(store, 1, 32, 650, 100000000); - pureAllocBatch(store, 1, 32, 3075, 300000); // cover wider range of blocks + pureAllocBatch(store, 1, 32, rw.m_maxFixedAlloc-4, 300000); // cover wider range of blocks store.commit(); System.out.println("Final allocations: " + rw.getTotalAllocations() + ", allocated bytes: " + rw.getTotalAllocationsSize() + ", file length: " @@ -1106,7 +1139,7 @@ .getBufferStrategy(); RWStore rw = bs.getRWStore(); - int freeAddr[] = new int[2048]; + int freeAddr[] = new int[512]; int freeCurs = 0; for (int i = 0; i < grp; i++) { int alloc = min + r.nextInt(sze-min); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-18 17:10:24
|
Revision: 3960 http://bigdata.svn.sourceforge.net/bigdata/?rev=3960&view=rev Author: thompsonbry Date: 2010-11-18 17:10:17 +0000 (Thu, 18 Nov 2010) Log Message: ----------- Hacked in an intgration with the RWStore to make it aware of the #of active transactions. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java 2010-11-18 16:50:22 UTC (rev 3959) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java 2010-11-18 17:10:17 UTC (rev 3960) @@ -237,8 +237,26 @@ protected AbstractLocalTransactionManager newLocalTransactionManager() { final JournalTransactionService abstractTransactionService = new JournalTransactionService( - properties, this).start(); + properties, this) { + + protected void activateTx(final TxState state) { + final IBufferStrategy bufferStrategy = Journal.this.getBufferStrategy(); + if(bufferStrategy instanceof RWStrategy) { + ((RWStrategy)bufferStrategy).getRWStore().activateTx(); + } + super.activateTx(state); + } + protected void deactivateTx(final TxState state) { + super.deactivateTx(state); + final IBufferStrategy bufferStrategy = Journal.this.getBufferStrategy(); + if(bufferStrategy instanceof RWStrategy) { + ((RWStrategy)bufferStrategy).getRWStore().deactivateTx(); + } + } + + }.start(); + return new AbstractLocalTransactionManager() { public AbstractTransactionService getTransactionService() { Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-18 16:50:22 UTC (rev 3959) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-18 17:10:17 UTC (rev 3960) @@ -444,6 +444,14 @@ // * the same txReleaseTime. // private static final int MAX_DEFERRED_FREE = 4094; // fits in 16k block private final long m_minReleaseAge; + + /** + * The #of open transactions (read-only or read-write). + * + * This is guarded by the {@link #m_allocationLock}. + */ + private int m_activeTxCount = 0; + private volatile long m_lastDeferredReleaseTime = 0L; // private final ArrayList<Integer> m_currentTxnFreeList = new ArrayList<Integer>(); private final PSOutputStream m_deferredFreeOut; @@ -1428,7 +1436,8 @@ * FIXME We need unit test when MIN_RELEASE_AGE is ZERO AND * there are open read-only transactions. */ - boolean alwaysDefer = m_minReleaseAge > 0L; + boolean alwaysDefer = m_minReleaseAge > 0L + || m_activeTxCount > 0; if (!alwaysDefer) alwaysDefer = context == null && !m_contexts.isEmpty(); if (alwaysDefer) @@ -4206,4 +4215,22 @@ return m_storageStats; } + public void activateTx() { + m_allocationLock.lock(); + try { + m_activeTxCount++; + } finally { + m_allocationLock.unlock(); + } + } + + public void deactivateTx() { + m_allocationLock.lock(); + try { + m_activeTxCount++; + } finally { + m_allocationLock.unlock(); + } + } + } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java 2010-11-18 16:50:22 UTC (rev 3959) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java 2010-11-18 17:10:17 UTC (rev 3960) @@ -183,10 +183,12 @@ // First, remove the existing tuples. removeWriteSet(unisolatedBTree); + store.commit(); + /* * Verify that the read-only view has not seen those changes. */ - { + if(false) { final BTree readOnlyBTree = (BTree) store.getIndex(name, tx2); verifyWriteSet1(readOnlyBTree); @@ -198,6 +200,8 @@ */ writeSet2(unisolatedBTree); + store.commit(); + /* * Verify that the read-only view has not seen those changes. * This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-18 18:17:28
|
Revision: 3965 http://bigdata.svn.sourceforge.net/bigdata/?rev=3965&view=rev Author: thompsonbry Date: 2010-11-18 18:17:22 +0000 (Thu, 18 Nov 2010) Log Message: ----------- Synching code to Martyn looking at blob alloc/release/deferred frees Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java 2010-11-18 17:49:55 UTC (rev 3964) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/Journal.java 2010-11-18 18:17:22 UTC (rev 3965) @@ -285,6 +285,7 @@ /** * Extended to shutdown the embedded transaction service. */ + @Override public void shutdown() { ((JournalTransactionService) getTransactionService()) @@ -297,6 +298,7 @@ /** * Extended to shutdown the embedded transaction service. */ + @Override public void shutdownNow() { ((JournalTransactionService) getTransactionService()) Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-18 17:49:55 UTC (rev 3964) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-11-18 18:17:22 UTC (rev 3965) @@ -851,15 +851,15 @@ try { - byte[] buf = new byte[1024 * 2048]; // 2Mb buffer of random data + final byte[] buf = new byte[1024 * 2048]; // 2Mb buffer of random data r.nextBytes(buf); - ByteBuffer bb = ByteBuffer.wrap(buf); + final ByteBuffer bb = ByteBuffer.wrap(buf); - RWStrategy bs = (RWStrategy) store + final RWStrategy bs = (RWStrategy) store .getBufferStrategy(); - RWStore rw = bs.getRWStore(); + final RWStore rw = bs.getRWStore(); long faddr = bs.write(bb); // rw.alloc(buf, buf.length); @@ -870,12 +870,16 @@ assertEquals(bb, rdBuf); // now delete the memory - bs.delete(faddr); // immediateFree! - + bs.delete(faddr); + + // verify immediateFree! + assertEquals(0L,bs.getPhysicalAddress(faddr)); + + // allocate another address, might (or might not) be the same. faddr = bs.write(bb); // rw.alloc(buf, buf.length); bb.position(0); - System.out.println("Now commit to disk"); + System.out.println("Now commit to disk (1)"); store.commit(); @@ -887,13 +891,26 @@ // now delete the memory bs.delete(faddr); + + // Must not have been immediately freed. + assertNotSame(0L, bs.getPhysicalAddress(faddr)); + + /* + * Commit before testing for deferred frees. Since there is a + * prior commit point, we are not allowed to immediately free + * any record from that commit point in order to preserve the + * consistency of the last commit point, so we have to commit + * first then test for deferred frees. + */ + System.out.println("Now commit to disk (2)"); - // since deferred frees, we must commit in order to ensure the - // address in invalid, indicating it is available for store.commit(); - rw.checkDeferredFrees(true, store); - + // Request release of deferred frees. + rw.checkDeferredFrees(true/* freeNow */, store); + + assertEquals(0L, bs.getPhysicalAddress(faddr)); + try { rdBuf = bs.read(faddr); // should fail with illegal argument throw new RuntimeException("Fail"); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2010-11-18 19:14:12
|
Revision: 3967 http://bigdata.svn.sourceforge.net/bigdata/?rev=3967&view=rev Author: thompsonbry Date: 2010-11-18 19:14:05 +0000 (Thu, 18 Nov 2010) Log Message: ----------- Added exception to help identify problems where the caller reading against a historical commit point is not using a read-only transaction and hence is not protected by a read-lock. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java Added Paths: ----------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PhysicalAddressResolutionException.java Added: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PhysicalAddressResolutionException.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PhysicalAddressResolutionException.java (rev 0) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PhysicalAddressResolutionException.java 2010-11-18 19:14:05 UTC (rev 3967) @@ -0,0 +1,54 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2010. All rights reserved. + +Contact: + SYSTAP, LLC + 4501 Tower Road + Greensboro, NC 27410 + lic...@bi... + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* + * Created on Nov 18, 2010 + */ + +package com.bigdata.rwstore; + +/** + * Exception thrown when a logical address maps onto a physical address which is + * not currently allocated. The most common cause of this exception is a read on + * the database using a historical commit point which is not protected by a read + * lock. You should be using a read-only transaction rather than a bare + * historical read in order to be protected by a read lock. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id$ + */ +public class PhysicalAddressResolutionException extends + IllegalArgumentException { + + /** + * + */ + private static final long serialVersionUID = 1L; + + public PhysicalAddressResolutionException(final long addr) { + + super("Address did not resolve to physical address: " + addr); + + } + +} Property changes on: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/PhysicalAddressResolutionException.java ___________________________________________________________________ Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-18 18:33:30 UTC (rev 3966) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-11-18 19:14:05 UTC (rev 3967) @@ -1258,12 +1258,7 @@ assertAllocators(); - final String msg = "Address did not resolve to physical address: " - + addr; - - log.warn(msg); - - throw new IllegalArgumentException(msg); + throw new PhysicalAddressResolutionException(addr); } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java 2010-11-18 18:33:30 UTC (rev 3966) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/samples/com/bigdata/samples/btree/JournalReadOnlyTxExample.java 2010-11-18 19:14:05 UTC (rev 3967) @@ -171,10 +171,20 @@ } - /* - * Open a read-only transaction on the last commit time. - */ - final long tx2 = store.newTx(ITx.READ_COMMITTED); + /* + * Open a read-only transaction on the last commit time. + * + * Note: If you use store.getLastCommitTime() here instead you will + * have a read-historical view of the same data, but that view is + * NOT protected by a read lock. Running the example with this + * change will cause the RWStore to throw out an exception since the + * writes will have overwritten the historical data by the time you + * try to read it. + */ + // Obtaining a tx here protects against recycling. +// final long tx2 = store.newTx(ITx.READ_COMMITTED); + // Using a historical read w/o a tx does NOT protect against recycling. + final long tx2 = store.getLastCommitTime(); try { // lookup the UNISOLATED B+Tree. @@ -186,30 +196,20 @@ store.commit(); /* - * Verify that the read-only view has not seen those changes. - */ - if(false) { - final BTree readOnlyBTree = (BTree) store.getIndex(name, tx2); - - verifyWriteSet1(readOnlyBTree); - - } - - /* * Write some new records on the unisolated index. */ writeSet2(unisolatedBTree); store.commit(); - - /* - * Verify that the read-only view has not seen those changes. - * - * Note: This probably hits the index cache and everything in - * the read-only B+Tree was already materialized when we - * verified it just before writing writeSet2 onto the unisolated - * index, so this is not really testing anything. - */ + + /* + * Verify that the read-only view has not seen those changes. + * + * Note: If you used a historical read rather than a read-only + * tx then this is where the RWStore will throw out an exception + * because the recycled has reused some of the records + * associated with the historical revision of the BTree. + */ { final BTree readOnlyBTree = (BTree) store.getIndex(name, tx2); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2010-12-16 13:05:00
|
Revision: 4010 http://bigdata.svn.sourceforge.net/bigdata/?rev=4010&view=rev Author: martyncutcher Date: 2010-12-16 12:44:43 +0000 (Thu, 16 Dec 2010) Log Message: ----------- 1) Fixes problem on RWStore open where a FixedAllocator can be associated with an incorrect free list. 2) Fixes issue with session protection interaction with WriteCacheService. ReleaseSession now clears transient writes from cache. 3) Fixes problem with session protection with FixedAllocator freebit count not kept in sync. Clears reported exceptions from concurrent stress tests. 4) Added extra validation to RWStore allocation access, validating IO requests against slot sizes. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/BufferMode.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/WORMStrategy.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/StorageStats.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Added Paths: ----------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/DirectFixedAllocator.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -992,6 +992,20 @@ } + case TemporaryRW: { + + /* + * Setup the buffer strategy. + */ + + _bufferStrategy = new RWStrategy(fileMetadata, quorum); + + this._rootBlock = fileMetadata.rootBlock; + + break; + + } + case Temporary: { /* @@ -2354,6 +2368,14 @@ * the store. */ final long commitRecordIndexAddr = _commitRecordIndex.writeCheckpoint(); + + /* + * DEBUG: The commitRecordIndexAddr should not be deleted, the + * call to lockAddress forces a runtime check protecting the address + */ + if (_bufferStrategy instanceof RWStrategy) { + ((RWStrategy) _bufferStrategy).lockAddress(commitRecordIndexAddr); + } if (quorum != null) { /* Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/BufferMode.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/BufferMode.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/BufferMode.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -139,6 +139,18 @@ /** * <p> + * A variant on the DiskRW backed by a temporary file. Options enable + * part of the store to be held with Direct ByteBuffers. A significant + * use case would be an in-memory store but with disk overflow if + * required. + * </p> + * + * @see RWStrategy + */ + TemporaryRW(false/* stable */, false/* fullyBuffered */,StoreTypeEnum.RW), + + /** + * <p> * A variant on the {@link #Disk} mode that is not restart-safe. This mode * is useful for all manners of temporary data with full concurrency control * and scales-up to very large temporary files. The backing file (if any) is Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -1262,14 +1262,14 @@ DiskOnlyStrategy(final long maximumExtent, final FileMetadata fileMetadata) { super(fileMetadata.extent, maximumExtent, fileMetadata.offsetBits, - fileMetadata.nextOffset, fileMetadata.bufferMode, + fileMetadata.nextOffset, fileMetadata.getBufferMode(), fileMetadata.readOnly); this.file = fileMetadata.file; this.fileMode = fileMetadata.fileMode; - this.temporaryStore = (fileMetadata.bufferMode==BufferMode.Temporary); + this.temporaryStore = (fileMetadata.getBufferMode()==BufferMode.Temporary); this.raf = fileMetadata.raf; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -802,6 +802,7 @@ log.info("Mapping file=" + file); buffer = opener.reopenChannel().map(FileChannel.MapMode.READ_WRITE, headerSize0, userExtent); break; + case TemporaryRW: case DiskRW: buffer = null; break; @@ -1514,4 +1515,8 @@ return getProperty(properties, name, defaultValue); } + public BufferMode getBufferMode() { + return bufferMode; + } + } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -633,4 +633,14 @@ } + /** + * An assert oriented method that allows a finite number of addresses + * to be monitored to ensure it is not freed. + * + * @param addr - address to be locked + */ + public void lockAddress(final long addr) { + m_store.lockAddress(decodeAddr(addr)); + } + } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/WORMStrategy.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -822,14 +822,14 @@ final Quorum<?, ?> quorum) { super(fileMetadata.extent, maximumExtent, fileMetadata.offsetBits, - fileMetadata.nextOffset, fileMetadata.bufferMode, + fileMetadata.nextOffset, fileMetadata.getBufferMode(), fileMetadata.readOnly); this.file = fileMetadata.file; this.fileMode = fileMetadata.fileMode; - this.temporaryStore = (fileMetadata.bufferMode==BufferMode.Temporary); + this.temporaryStore = (fileMetadata.getBufferMode()==BufferMode.Temporary); this.raf = fileMetadata.raf; Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -26,6 +26,8 @@ import java.util.ArrayList; +import org.apache.log4j.Logger; + import com.bigdata.rwstore.RWStore.AllocationStats; /** @@ -43,6 +45,15 @@ * @todo change to use long[]s. */ public class AllocBlock { + + private static final Logger log = Logger.getLogger(AllocBlock.class); + + /** + * The FixedAllocator owning this block. The callback reference is needed + * to allow the AllocBlock to determine the session state and whether to + * clear the transient bits. + */ + final FixedAllocator m_allocator; /** * The address of the {@link AllocBlock} -or- ZERO (0) if {@link AllocBlock} * has not yet been allocated on the persistent heap. Note that the space @@ -82,8 +93,9 @@ // */ // private final RWWriteCacheService m_writeCache; - AllocBlock(final int addrIsUnused, final int bitSize) {//, final RWWriteCacheService cache) { + AllocBlock(final int addrIsUnused, final int bitSize, final FixedAllocator allocator) {//, final RWWriteCacheService cache) { // m_writeCache = cache; + m_allocator = allocator; m_ints = bitSize; m_commit = new int[bitSize]; m_live = new int[bitSize]; @@ -116,6 +128,16 @@ } public boolean freeBit(final int bit) { + // by default do NOT session protect, the 2 argument call is made + // directly from the RWStore that has access to sessio and transaction + // state + return freeBit(bit, false); + } + + /* + * + */ + public boolean freeBit(final int bit, final boolean sessionProtect) { if (!RWStore.tstBit(m_live, bit)) { throw new IllegalArgumentException("Freeing bit not set"); } @@ -128,17 +150,35 @@ * Note that with buffered IO there is also an opportunity to avoid * output to the file by removing any pending write to the now freed * address. On large transaction scopes this may be significant. + * + * The sessionProtect parameter indicates whether we really should + * continue to protect this alloction by leaving the transient bit + * set. For general session protection we should, BUT it allocation + * contexts have been used we can allow immediate recycling and this + * is setup by the caller */ RWStore.clrBit(m_live, bit); + + if (log.isTraceEnabled()) { + log.trace("Freeing " + bitPhysicalAddress(bit) + " sessionProtect: " + sessionProtect); + } - if (!RWStore.tstBit(m_commit, bit)) { - RWStore.clrBit(m_transients, bit); - - return true; + if (!sessionProtect) { + if (!RWStore.tstBit(m_commit, bit)) { + RWStore.clrBit(m_transients, bit); + + return true; + } else { + return false; + } } else { return false; } } + + private long bitPhysicalAddress(int bit) { + return RWStore.convertAddr(m_addr) + ((long) m_allocator.m_size * bit); + } /** * The shadow, if non-null defines the context for this request. @@ -266,14 +306,45 @@ * of the committed bits and the live bits, but rather an ORing of the live * with all the committed bits since the start of the session. * When the session is released, the state is restored to an ORing of the - * live and the committed, thus releasing slots for re-allocation. + * live and the committed, thus releasing slots for re-allocation. + * + * For each transient bit, check if cleared and ensure any write is removed + * from the write cache. Where the bit is set in the session protected + * but not in the recalculated transient. Tested with new &= ~old; + * + * @param cache */ - public void releaseSession() { + public void releaseSession(RWWriteCacheService cache) { if (m_addr != 0) { // check active! for (int i = 0; i < m_live.length; i++) { + int chkbits = m_transients[i]; m_transients[i] = m_live[i] | m_commit[i]; + chkbits &= ~m_transients[i]; + + if (chkbits != 0) { + // there are writes to clear + for (int b = 0; b < 32; b++) { + if ((chkbits & (1 << b)) != 0) { + long clr = RWStore.convertAddr(m_addr) + ((long) m_allocator.m_size * b); + + if (log.isTraceEnabled()) + log.trace("releasing address: " + clr); + + cache.clearWrite(clr); + } + } + } } } } + public String show() { + StringBuilder sb = new StringBuilder(); + sb.append("AllocBlock, baseAddress: " + RWStore.convertAddr(m_addr) + " bits: "); + for (int b: m_transients) + sb.append(b + " "); + + return sb.toString(); + } + } Added: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/DirectFixedAllocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/DirectFixedAllocator.java (rev 0) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/DirectFixedAllocator.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -0,0 +1,18 @@ +package com.bigdata.rwstore; + +/** + * The DirectFixedAllocator is used to manage in-memory Direct ByteBuffer + * allocated memory. + * + */ +public class DirectFixedAllocator extends FixedAllocator { + + DirectFixedAllocator(RWStore store, int size) { + super(store, size); + } + + protected int grabAllocation(RWStore store, int blockSize) { + return store.allocateDirect(blockSize); + } + +} Property changes on: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/DirectFixedAllocator.java ___________________________________________________________________ Added: svn:mime-type + text/plain Added: svn:keywords + Id Date Revision Author HeadURL Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -114,7 +114,7 @@ final int bit = offset % allocBlockRange; if (RWStore.tstBit(block.m_live, bit) - || (this.m_sessionActive && RWStore.tstBit(block.m_transients, bit))) + || (m_sessionActive && RWStore.tstBit(block.m_transients, bit))) { return RWStore.convertAddr(block.m_addr) + ((long) m_size * bit); } else { @@ -155,7 +155,7 @@ * store from re-allocating allocations reachable from read-only * requests and concurrent transactions. */ - private boolean m_sessionActive; + boolean m_sessionActive; public void setAllocationContext(final IAllocationContext context) { if (context == null && m_context != null) { @@ -196,13 +196,11 @@ public byte[] write() { try { final AllocBlock fb = m_allocBlocks.get(0); - if (log.isDebugEnabled()) - log.debug("writing allocator " + m_index + " for " + getStartAddr() + " with " + fb.m_live[0]); + if (log.isTraceEnabled()) + log.trace("writing allocator " + m_index + " for " + getStartAddr() + " with " + fb.m_live[0]); final byte[] buf = new byte[1024]; final DataOutputStream str = new DataOutputStream(new FixedOutputStream(buf)); try { - m_sessionActive = m_store.isSessionProtected(); - str.writeInt(m_size); final Iterator<AllocBlock> iter = m_allocBlocks.iterator(); @@ -240,19 +238,19 @@ str.close(); } -// if (!m_store.isSessionPreserved()) { - m_freeBits += m_freeTransients; - - // Handle re-addition to free list once transient frees are - // added back - if ((m_freeTransients == m_freeBits) && (m_freeTransients != 0)) { - m_freeList.add(this); - m_freeWaiting = false; + if (!this.m_sessionActive) { + m_freeBits += m_freeTransients; + + // Handle re-addition to free list once transient frees are + // added back + if ((m_freeTransients == m_freeBits) && (m_freeTransients != 0)) { + m_freeList.add(this); + m_freeWaiting = false; + } + + m_freeTransients = 0; } - m_freeTransients = 0; -// } - return buf; } catch (IOException e) { throw new StorageTerminalError("Error on write", e); @@ -309,7 +307,7 @@ } /** The size of the allocation slots in bytes. */ - private final int m_size; + final int m_size; private int m_startAddr = 0; private int m_endAddr = 0; @@ -343,11 +341,13 @@ m_size = size; - m_bitSize = calcBitSize(true, size, cMinAllocation, cModAllocation); + // By default, disk-based allocators should optimise for density + m_bitSize = calcBitSize(true /* optDensity */, size, cMinAllocation, cModAllocation); -// m_writeCache = cache; - // number of blocks in this allocator, bitSize plus 1 for start address + // The 1K allocator is 256 ints, one is used to record the slot size and + // another for the checksum; leaving 254 to be used to store the + // AllocBlocks. final int numBlocks = 254 / (m_bitSize + 1); /* @@ -357,7 +357,7 @@ */ m_allocBlocks = new ArrayList<AllocBlock>(numBlocks); for (int i = 0; i < numBlocks; i++) { - m_allocBlocks.add(new AllocBlock(0, m_bitSize));//, cache)); + m_allocBlocks.add(new AllocBlock(0, m_bitSize, this));//, cache)); } m_freeTransients = 0; @@ -415,7 +415,7 @@ * content and 1 more for the header). A variation on the current Blob * implementation could include the header in the first allocation, thus * reducing the minimum Blob allocations from 3 to 2, but the point still - * holds that too small a max fixed allocation could rmatically reduce the + * holds that too small a max fixed allocation could dramatically reduce the * number of allocations that could be made. * * @param alloc the slot size to be managed @@ -435,8 +435,6 @@ while ((nints * intAllocation) % modAllocation != 0) nints++; -// System.out.println("calcBitSize for " + alloc + " returns " + nints); - return nints; } @@ -498,6 +496,10 @@ private boolean m_freeWaiting = true; public boolean free(final int addr, final int size) { + return free(addr, size, false); + } + + public boolean free(final int addr, final int size, final boolean overideSession) { if (addr < 0) { final int offset = ((-addr) & RWStore.OFFSET_BITS_MASK) - 3; // bit adjust @@ -505,15 +507,24 @@ final int block = offset/nbits; + m_sessionActive = m_store.isSessionProtected(); + if (((AllocBlock) m_allocBlocks.get(block)) - .freeBit(offset % nbits)) { // bit adjust + .freeBit(offset % nbits, m_sessionActive && !overideSession)) { // bit adjust - // Only add back to the free list if at least 3000 bits avail - if (m_freeBits++ == 0 && false) { + // Only add back to the free list this is a DirectFixedAllocator + // or the freeBits exceed the cDefaultFreeBitsThreshold + // If a DirectFixedAllocator then also ensure it is added to the + // front of the free list + if (m_freeBits++ == 0 && this instanceof DirectFixedAllocator) { m_freeWaiting = false; - m_freeList.add(this); + m_freeList.add(0, this); } else if (m_freeWaiting && m_freeBits == m_store.cDefaultFreeBitsThreshold) { m_freeWaiting = false; + + if (log.isDebugEnabled()) + log.debug("Returning Allocator to FreeList - " + m_size); + m_freeList.add(this); } } else { @@ -554,6 +565,11 @@ throw new IllegalArgumentException( "Allocate requires positive size, got: " + size); + if (size > m_size) + throw new IllegalArgumentException( + "FixedAllocator with slots of " + m_size + + " bytes requested allocation for "+ size + " bytes"); + int addr = -1; final Iterator<AllocBlock> iter = m_allocBlocks.iterator(); @@ -570,9 +586,9 @@ blockSize *= m_size; blockSize >>= RWStore.ALLOCATION_SCALEUP; - block.m_addr = store.allocBlock(blockSize); - if (log.isInfoEnabled()) - log.info("Allocation block at " + block.m_addr + " of " + (blockSize << 16) + " bytes"); + block.m_addr = grabAllocation(store, blockSize); + if (log.isDebugEnabled()) + log.debug("Allocation block at " + block.m_addr + " of " + (blockSize << 16) + " bytes"); if (m_startAddr == 0) { m_startAddr = block.m_addr; @@ -583,8 +599,9 @@ } if (addr != -1) { - addr += 3; // Tweak to ensure non-zero address for offset 0 + addr += 3; // Tweak to ensure non-zero address for offset 0 + if (--m_freeBits == 0) { if (log.isTraceEnabled()) log.trace("Remove from free list"); @@ -593,9 +610,10 @@ // Should have been first on list, now check for first if (m_freeList.size() > 0) { - final FixedAllocator nxt = (FixedAllocator) m_freeList.get(0); - if (log.isInfoEnabled()) - log.info("Freelist head: " + nxt.getSummaryStats()); + if (log.isDebugEnabled()) { + final FixedAllocator nxt = (FixedAllocator) m_freeList.get(0); + log.debug("Freelist head: " + nxt.getSummaryStats()); + } } } @@ -606,16 +624,28 @@ if (m_statsBucket != null) { m_statsBucket.allocate(size); } - + return value; } else { - if (log.isTraceEnabled()) - log.trace("FixedAllocator returning null address"); - + if (log.isDebugEnabled()) { + StringBuilder sb = new StringBuilder(); + sb.append("FixedAllocator returning null address, with freeBits: " + m_freeBits + "\n"); + + for (AllocBlock ab: m_allocBlocks) { + sb.append(ab.show() + "\n"); + } + + log.debug(sb); + } + return 0; } } + protected int grabAllocation(RWStore store, int blockSize) { + return store.allocBlock(blockSize); + } + public boolean hasFree() { return m_freeBits > 0; } @@ -764,12 +794,12 @@ m_statsBucket = b; } - public void releaseSession() { + public void releaseSession(RWWriteCacheService cache) { if (this.m_sessionActive) { if (log.isTraceEnabled()) log.trace("Allocator: #" + m_index + " releasing session protection"); for (AllocBlock ab : m_allocBlocks) { - ab.releaseSession(); + ab.releaseSession(cache); } } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/IStore.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -77,6 +77,12 @@ */ public void getData(long l, byte buf[]); + /************************************************************** + * @param addr - the address + * @return the size of the slot associated + */ + public int getAssociatedSlotSize(int addr); + // /************************************************************** // * Given a physical address (byte offset on the store), return true // * if that address could be managed by an allocated block. Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -37,6 +37,8 @@ import java.util.Collections; import java.util.Iterator; import java.util.Map; +import java.util.TreeMap; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; @@ -54,6 +56,7 @@ import com.bigdata.counters.CounterSet; import com.bigdata.counters.Instrument; import com.bigdata.counters.striped.StripedCounters; +import com.bigdata.io.DirectBufferPool; import com.bigdata.io.FileChannelUtility; import com.bigdata.io.IReopenChannel; import com.bigdata.io.writecache.BufferedWrite; @@ -61,6 +64,7 @@ import com.bigdata.io.writecache.WriteCacheService; import com.bigdata.journal.AbstractBufferStrategy; import com.bigdata.journal.AbstractJournal; +import com.bigdata.journal.BufferMode; import com.bigdata.journal.CommitRecordIndex; import com.bigdata.journal.CommitRecordSerializer; import com.bigdata.journal.FileMetadata; @@ -194,9 +198,9 @@ * <p> * Add metabits header record checksum field and verify on read back. * <p> - * Checksum fixed allocators (needs to be tested on read back). + * Done. Checksum fixed allocators (needs to be tested on read back). * <p> - * Add version field to the fixed allocator. + * Done. Add version field to the fixed allocator. * <p> * Done. Checksum delete blocks / blob records. * <p> @@ -207,7 +211,7 @@ * Modify FixedAllocator to use arrayCopy() rather than clone and * declare more fields to be final. See notes on {@link AllocBlock}. * <p> - * Implement logic to "abort" a shadow allocation context. + * Done. Implement logic to "abort" a shadow allocation context. * <p> * Unit test to verify that we do not recycle allocations from the last * commit point even when the retention time is zero such that it is @@ -335,6 +339,12 @@ // m_commitCallback = callback; // } + // If required, then allocate 1M direct buffers + private static final int cDirectBufferCapacity = 1024 * 1024; + + private int cMaxDirectBuffers = 20; // 20M of direct buffers + static final int cDirectAllocationOffset = 64 * 1024; + // /////////////////////////////////////////////////////////////////////////////////////// // RWStore Data // /////////////////////////////////////////////////////////////////////////////////////// @@ -483,11 +493,26 @@ private StorageStats m_storageStats; private long m_storageStatsAddr = 0; + /** + * Direct ByteBuffer allocations. + * + * TODO: Support different scaleups for disk and direct allocation to + * allow for finer granularity of allocation. For example, a 1K + * scaleup would allow 32bit slot allocations for all slot sizes. + */ + private int m_directSpaceAvailable = 0; + private int m_nextDirectAllocation = cDirectAllocationOffset; + private ArrayList<ByteBuffer> m_directBuffers = null; + + private final boolean m_enableDirectBuffer; + /** * <code>true</code> iff the backing store is open. */ private volatile boolean m_open = true; + private TreeMap<Integer, Integer> m_lockAddresses = null; + class WriteCacheImpl extends WriteCache.FileChannelScatteredWriteCache { public WriteCacheImpl(final ByteBuffer buf, final boolean useChecksum, @@ -549,13 +574,23 @@ if (fileMetadata == null) throw new IllegalArgumentException(); - this.m_minReleaseAge = LongValidator.GTE_ZERO.parse( + this.m_minReleaseAge = Long.valueOf(fileMetadata.getProperty( AbstractTransactionService.Options.MIN_RELEASE_AGE, - AbstractTransactionService.Options.DEFAULT_MIN_RELEASE_AGE); + AbstractTransactionService.Options.DEFAULT_MIN_RELEASE_AGE)); if (log.isInfoEnabled()) log.info(AbstractTransactionService.Options.MIN_RELEASE_AGE + "=" + m_minReleaseAge); + /* + * Disable TemporaryRW option for now + */ + // m_enableDirectBuffer = fileMetadata.getBufferMode() == BufferMode.TemporaryRW; + m_enableDirectBuffer = false; + + if (m_enableDirectBuffer) { + m_directBuffers = new ArrayList<ByteBuffer>(); + addDirectBuffer(); + } cDefaultMetaBitsSize = Integer.valueOf(fileMetadata.getProperty( Options.META_BITS_SIZE, @@ -673,6 +708,8 @@ for (FixedAllocator fa: m_allocs) { m_storageStats.register(fa); } + } else { + m_storageStats = new StorageStats(m_allocSizes); } } @@ -694,7 +731,15 @@ } } - private void setAllocations(final FileMetadata fileMetadata) + private void addDirectBuffer() { + if (cMaxDirectBuffers > m_directBuffers.size()) { + ByteBuffer bbuf = ByteBuffer.allocateDirect(cDirectBufferCapacity); + m_directBuffers.add(bbuf); + m_directSpaceAvailable += cDirectBufferCapacity; + } + } + + private void setAllocations(final FileMetadata fileMetadata) throws IOException { final String buckets = fileMetadata.getProperty( @@ -1017,11 +1062,20 @@ final ArrayList<? extends Allocator> freeList; assert allocSize > 0; + // m_minFixedAlloc and m_maxFixedAlloc may not be set since + // as finals they must be set in the constructor. Therefore + // recalculate for local load + final int minFixedAlloc = 64 * m_allocSizes[0]; + final int maxFixedAlloc = 64 * m_allocSizes[m_allocSizes.length-1]; int index = 0; - int fixedSize = m_minFixedAlloc; - while (fixedSize < allocSize) + int fixedSize = minFixedAlloc; + while (fixedSize < allocSize && fixedSize < maxFixedAlloc) fixedSize = 64 * m_allocSizes[++index]; + if (allocSize != fixedSize) { + throw new IllegalStateException("Unexpected allocator size: " + + allocSize + " != " + fixedSize); + } allocator = new FixedAllocator(this, allocSize);//, m_writeCache); freeList = m_freeFixed[index]; @@ -1056,13 +1110,6 @@ for (int index = 0; index < m_allocs.size(); index++) { ((Allocator) m_allocs.get(index)).setIndex(index); } - - if (false) { - StringBuilder tmp = new StringBuilder(); - showAllocators(tmp); - - System.out.println("Allocators: " + tmp.toString()); - } } /** @@ -1206,6 +1253,8 @@ readLock.lock(); + assertOpen(); // check again after taking lock + try { // length includes space for the checksum if (length > m_maxFixedAlloc) { @@ -1277,6 +1326,10 @@ } try { + + if (getBlock((int) addr).getBlockSize() < length) { + throw new IllegalStateException("Bad Address: length requested greater than allocated slot"); + } final long paddr = physicalAddress((int) addr); @@ -1287,6 +1340,12 @@ throw new PhysicalAddressResolutionException(addr); } + + if (paddr < 0) { // read from Direct ByteBuffer + directRead(paddr, buf, offset, length); + + return; + } /** * Check WriteCache first @@ -1382,6 +1441,69 @@ } } + /** + * Retrieves data from the direct byte buffers, must handle transfers across + * multiple buffers + */ + private void directRead(final long paddr, final byte[] buf, final int offset, final int length) { + assert paddr < 0; + assert m_directBuffers != null; + + final int baddr = (int) (-paddr) - cDirectAllocationOffset; // buffer address + int bufIndex = baddr / cDirectBufferCapacity; + int bufOffset = baddr % cDirectBufferCapacity; + + int transfer = 0; + int curOut = offset; + + while (transfer < length) { + ByteBuffer direct = m_directBuffers.get(bufIndex); + direct.position(bufOffset); + int avail = cDirectBufferCapacity - bufOffset; + int req = length - transfer; + int tlen = avail < req ? avail : req; + + direct.get(buf, curOut, tlen); + + transfer += tlen; + curOut += tlen; + + bufIndex++; + bufOffset = 0; + } + } + + /** + * Writes to direct buffers, transferring across boundaries as required + */ + private void directWrite(final long pa, final byte[] buf, final int offset, final int length, final int chk) { + assert pa < 0; + assert m_directBuffers != null; + + final int baddr = (int) (-pa) - cDirectAllocationOffset; // buffer address + int bufIndex = baddr / cDirectBufferCapacity; + int bufOffset = baddr % cDirectBufferCapacity; + + int transfer = 0; + int curIn = offset; + + while (transfer < length) { + ByteBuffer direct = m_directBuffers.get(bufIndex); + direct.position(bufOffset); + int avail = cDirectBufferCapacity - bufOffset; + int req = length - transfer; + int tlen = avail < req ? avail : req; + + direct.put(buf, curIn, tlen); + + transfer += tlen; + curIn += tlen; + + bufIndex++; + bufOffset = 0; + } + } + private void assertAllocators() { for (int i = 0; i < m_allocs.size(); i++) { if (m_allocs.get(i).getIndex() != i) { @@ -1434,7 +1556,7 @@ public void free(final long laddr, final int sze, final IAllocationContext context) { assertOpen(); final int addr = (int) laddr; - + switch (addr) { case 0: case -1: @@ -1443,6 +1565,9 @@ } m_allocationLock.lock(); try { + if (m_lockAddresses != null && m_lockAddresses.containsKey((int)laddr)) + throw new IllegalStateException("address locked: " + laddr); + if (sze > m_maxFixedAlloc-4) { freeBlob(addr, sze, context); } else { @@ -1464,35 +1589,32 @@ * FIXME We need unit test when MIN_RELEASE_AGE is ZERO AND * there are open read-only transactions. */ - boolean alwaysDefer = m_minReleaseAge > 0L - || m_activeTxCount > 0; - if (!alwaysDefer) - alwaysDefer = context == null && !m_contexts.isEmpty(); - if (alwaysDefer) - if (log.isDebugEnabled()) - log.debug("Should defer " + addr + " real: " - + physicalAddress(addr)); - if (alwaysDefer - || !alloc.canImmediatelyFree(addr, sze, context)) { - deferFree(addr, sze); + if (m_minReleaseAge == 0) { + /* + * The session protection is complicated by the mix of + * transaction protection and isolated AllocationContexts. + */ + if (this.isSessionProtected()) { + + immediateFree(addr, sze, context != null && alloc.canImmediatelyFree(addr, sze, context)); + } else { + immediateFree(addr, sze); + } } else { - immediateFree(addr, sze); + boolean alwaysDefer = m_activeTxCount > 0; + + if (!alwaysDefer) + alwaysDefer = context == null && !m_contexts.isEmpty(); + + if (alwaysDefer) + if (log.isDebugEnabled()) + log.debug("Should defer " + addr + " real: " + physicalAddress(addr)); + if (alwaysDefer || !alloc.canImmediatelyFree(addr, sze, context)) { + deferFree(addr, sze); + } else { + immediateFree(addr, sze); + } } -// if (m_minReleaseAge == 0) { -// immediateFree(addr, sze); -// } else { -// boolean alwaysDefer = m_activeTxCount > 0; -// if (!alwaysDefer) -// alwaysDefer = context == null && !m_contexts.isEmpty(); -// if (alwaysDefer) -// if (log.isDebugEnabled()) -// log.debug("Should defer " + addr + " real: " + physicalAddress(addr)); -// if (alwaysDefer || !alloc.canImmediatelyFree(addr, sze, context)) { -// deferFree(addr, sze); -// } else { -// immediateFree(addr, sze); -// } -// } } } finally { m_allocationLock.unlock(); @@ -1504,6 +1626,19 @@ return m_minReleaseAge; } + /** + * Session protection can only be used in preference to deferred frees when + * the minReleaseAge is zero. If so then two protection states are checked: + * either a positive activeTxCount incremented by the TransactionManager + * or if there are active AllocationContexts. + * + * The activeTxCount esentially protects read-only transactions while the + * AllocationContexts enable concurrent store allocations, whilst also + * supporting immediate re-cycling of localized allocations (those made + * and released within the same AllocationContext). + * + * @return whether there is a logical active session + */ boolean isSessionProtected() { return m_minReleaseAge == 0 && (m_activeTxCount > 0 || !m_contexts.isEmpty()); } @@ -1515,11 +1650,16 @@ * * When called, will call through to the Allocators to re-sync the * transient bits with the committed and live. + * + * The writeCache is passed into the allocator to enable any "now free" + * allocations to be cleared from the cache. Until the session is released + * the writeCache must be maintained to support readers of uncommitted and + * unwritten allocations. */ void releaseSessions() { if (m_minReleaseAge == 0) { for (FixedAllocator fa : m_allocs) { - fa.releaseSession(); + fa.releaseSession(m_writeCache); } } } @@ -1559,6 +1699,10 @@ // private long immediateFreeCount = 0; private void immediateFree(final int addr, final int sze) { + immediateFree(addr, sze, false); + } + + private void immediateFree(final int addr, final int sze, final boolean overrideSession) { switch (addr) { case 0: @@ -1575,14 +1719,18 @@ throw new IllegalArgumentException("Invalid address provided to immediateFree: " + addr + ", size: " + sze); } final long pa = alloc.getPhysicalAddress(addrOffset); + if (log.isTraceEnabled()) log.trace("Freeing allocation at " + addr + ", physical address: " + pa); - alloc.free(addr, sze); + alloc.free(addr, sze, overrideSession); // must clear after free in case is a blobHdr that requires reading! // the allocation lock protects against a concurrent re-allocation // of the address before the cache has been cleared assert pa != 0; - m_writeCache.clearWrite(pa); + // only clear any existing write to cache if no active session + if (overrideSession || !this.isSessionProtected()) { + m_writeCache.clearWrite(pa); + } m_frees++; if (alloc.isAllocated(addrOffset)) throw new IllegalStateException("Reallocation problem with WriteCache"); @@ -1649,7 +1797,12 @@ final ArrayList<FixedAllocator> list = m_freeFixed[i]; if (list.size() == 0) { - allocator = new FixedAllocator(this, block);//, m_writeCache); + if (canAllocateDirect()) { + allocator = new DirectFixedAllocator(this, block); + } else { + allocator = new FixedAllocator(this, block); + } + allocator.setFreeList(list); allocator.setIndex(m_allocs.size()); @@ -1707,6 +1860,13 @@ } } + /** + * @return true if we have spare directBuffers. + */ + private boolean canAllocateDirect() { + return m_directBuffers != null && m_directBuffers.size() < cMaxDirectBuffers; + } + private int fixedAllocatorIndex(final int size) { int i = 0; @@ -1788,13 +1948,23 @@ } final int newAddr = alloc(size + 4, context); // allow size for checksum + + if (newAddr == 0) + throw new IllegalStateException("NULL address allocated"); final int chk = ChecksumUtility.getCHK().checksum(buf, size); + + final long pa = physicalAddress(newAddr); - try { - m_writeCache.write(physicalAddress(newAddr), ByteBuffer.wrap(buf, 0, size), chk); - } catch (InterruptedException e) { - throw new RuntimeException("Closed Store?", e); + // if from DirectFixedAllocator then physical address will be negative + if (pa < 0) { + directWrite(pa, buf, 0, size, chk); + } else { + try { + m_writeCache.write(pa, ByteBuffer.wrap(buf, 0, size), chk); + } catch (InterruptedException e) { + throw new RuntimeException("Closed Store?", e); + } } // Update counters. @@ -1875,12 +2045,19 @@ // } // } - /** + /** * Toss away all buffered writes and then reload from the current root * block. + * + * If the store is using DirectFixedAllocators then an IllegalStateException + * is thrown */ public void reset() { assertOpen(); + + if (m_directBuffers != null) + throw new IllegalStateException("Reset is not supported with direct buffers"); + if (log.isInfoEnabled()) { log.info("RWStore Reset"); } @@ -1915,7 +2092,7 @@ // notify of current file length. m_writeCache.setExtent(convertAddr(m_fileSize)); } catch (Exception e) { - throw new IllegalStateException("Unable reset the store", e); + throw new IllegalStateException("Unable to reset the store", e); } finally { m_allocationLock.unlock(); } @@ -1971,10 +2148,14 @@ if (addr == 0) { throw new IllegalStateException("Invalid metabits address: " + m_metaBitsAddr); } - try { - m_writeCache.write(addr, ByteBuffer.wrap(buf), 0, false); - } catch (InterruptedException e) { - throw new RuntimeException(e); + if (addr < 0) { + directWrite(addr, buf, 0, buf.length, 0); + } else { + try { + m_writeCache.write(addr, ByteBuffer.wrap(buf), 0, false); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } } @@ -1993,8 +2174,11 @@ try { - checkDeferredFrees(true, journal); // free now if possible + final int totalFreed = checkDeferredFrees(true, journal); // free now if possible + if (totalFreed > 0 && log.isInfoEnabled()) { + log.info("Freed " + totalFreed + " deferralls on commit"); + } // free old storageStatsAddr if (m_storageStatsAddr != 0) { int len = (int) (m_storageStatsAddr & 0xFFFF); @@ -2017,14 +2201,14 @@ throw new IllegalStateException("Returned MetaBits Address not valid!"); } - // TODO: assert that m_deferredFreeOut is empty! - assert m_deferredFreeOut.getBytesWritten() == 0; - // Call immediateFree - no need to defer freeof metaBits, this // has to stop somewhere! // No more allocations must be made immediateFree((int) oldMetaBits, oldMetaBitsSize); + // There must be no buffered deferred frees + assert m_deferredFreeOut.getBytesWritten() == 0; + // save allocation headers final Iterator<Allocator> iter = m_commitList.iterator(); while (iter.hasNext()) { @@ -2097,8 +2281,10 @@ * <p> * Note: This method is package private in order to expose it to the unit * tests. + * + * returns number of addresses freed */ - /* public */void checkDeferredFrees(final boolean freeNow, + /* public */int checkDeferredFrees(final boolean freeNow, final Journal journal) { // Note: Invoked from unit test w/o the lock... @@ -2140,9 +2326,11 @@ * Note: This adds one to the lastDeferredReleaseTime to give * exclusive lower bound semantics. */ - freeDeferrals(journal, m_lastDeferredReleaseTime + 1, + return freeDeferrals(journal, m_lastDeferredReleaseTime + 1, latestReleasableTime); + } else { + return 0; } } @@ -2397,31 +2585,6 @@ return ret; } -// /* -// * clear -// * -// * reset the file size commit the root blocks -// */ -// public void clear() { -// try { -// baseInit(); -// -// m_fileSize = -4; -// m_metaStartAddr = m_fileSize; -// m_nextAllocation = -1; // keep on a 8K boundary (8K minimum -// // allocation) -// m_raf.setLength(convertAddr(m_fileSize)); -// -// m_curHdrAddr = 0; -// m_rootAddr = 0; -// -// startTransaction(); -// commitTransaction(); -// } catch (Exception e) { -// throw new StorageTerminalError("Unable to clear store", e); -// } -// } - public static long convertAddr(final int addr) { final long laddr = addr; if (laddr < 0) { @@ -2587,36 +2750,6 @@ return -1; } - -// // -------------------------------------------------------------------------------------- -// private String allocListStats(final List<Allocator> list, final AtomicLong counter) { -// final StringBuffer stats = new StringBuffer(); -// final Iterator<Allocator> iter = list.iterator(); -// while (iter.hasNext()) { -// stats.append(iter.next().getStats(counter)); -// } -// -// return stats.toString(); -// } -// -// public String getStats(final boolean full) { -// -// final AtomicLong counter = new AtomicLong(); -// -// final StringBuilder sb = new StringBuilder("FileSize : " + m_fileSize -// + " allocated : " + m_nextAllocation + "\r\n"); -// -// if (full) { -// -// sb.append(allocListStats(m_allocs, counter)); -// -// sb.append("Allocated : " + counter); -// -// } -// -// return sb.toString(); -// -// } public static class AllocationStats { public AllocationStats(final int i) { @@ -2626,11 +2759,29 @@ long m_reservedSlots; long m_filledSlots; } - /** - * Collected statistics are against each Allocation Block size. See - * {@link StorageStats#showStats(StringBuilder)} for details on the - * generated report. + * Utility debug outputing the allocator array, showing index, start + * address and alloc type/size + * + * Collected statistics are against each Allocation Block size: + * total number of slots | store size + * number of filled slots | store used + * <dl> + * <dt>AllocatorSize</dt><dd>The #of bytes in the allocated slots issued by this allocator.</dd> + * <dt>AllocatorCount</dt><dd>The #of fixed allocators for that slot size.</dd> + * <dt>SlotsInUse</dt><dd>The difference between the two previous columns (net slots in use for this slot size).</dd> + * <dt>SlotsReserved</dt><dd>The #of slots in this slot size which have had storage reserved for them.</dd> + * <dt>SlotsAllocated</dt><dd>Cumulative allocation of slots to date in this slot size (regardless of the transaction outcome).</dd> + * <dt>SlotsRecycled</dt><dd>Cumulative recycled slots to date in this slot size (regardless of the transaction outcome).</dd> + * <dt>SlotsChurn</dt><dd>How frequently slots of this size are re-allocated (SlotsInUse/SlotsAllocated).</dd> + * <dt>%SlotsUnused</dt><dd>The percentage of slots of this size which are not in use (1-(SlotsInUse/SlotsReserved)).</dd> + * <dt>BytesReserved</dt><dd>The space reserved on the backing file for those allocation slots</dd> + * <dt>BytesAppData</dt><dd>The #of bytes in the allocated slots which are used by application data (including the record checksum).</dd> + * <dt>%SlotWaste</dt><dd>How well the application data fits in the slots (BytesAppData/(SlotsInUse*AllocatorSize)).</dd> + * <dt>%AppData</dt><dd>How much of your data is stored by each allocator (BytesAppData/Sum(BytesAppData)).</dd> + * <dt>%StoreFile</dt><dd>How much of the backing file is reserved for each allocator (BytesReserved/Sum(BytesReserved)).</dd> + * <dt>%StoreWaste</dt><dd>How much of the total waste on the store is waste for this allocator size ((BytesReserved-BytesAppData)/(Sum(BytesReserved)-Sum(BytesAppData))).</dd> + * </dl> */ public void showAllocators(final StringBuilder str) { m_storageStats.showStats(str); @@ -2761,8 +2912,8 @@ final FixedAllocator allocator = getBlock(addr); final int offset = getOffset(addr); final long laddr = allocator.getPhysicalAddress(offset); - - return laddr; + + return allocator instanceof DirectFixedAllocator ? -laddr : laddr; } } @@ -2790,10 +2941,6 @@ return alloc; } -// private int blockIndex(int addr) { -// return (-addr) >>> OFFSET_BITS; -// } - private FixedAllocator getBlock(final int addr) { final int index = (-addr) >>> OFFSET_BITS; @@ -2804,24 +2951,6 @@ return (-addr) & OFFSET_BITS_MASK; // OFFSET_BITS } -// public int addr2Size(final int addr) { -// if (addr > 0) { -// int size = 0; -// -// final int index = ((int) addr) % 16; -// -// if (index == 15) { // blob -// throw new Error("FIX ME : legacy BLOB code being accessed somehow"); -// } else { -// size = m_minFixedAlloc * m_allocSizes[index]; -// } -// -// return size; -// } else { -// return getBlock(addr).getPhysicalSize(getOffset(addr)); -// } -// } - /** * The {@link RWStore} always generates negative address values. * @@ -2831,150 +2960,10 @@ return addr <= 0; } -// /******************************************************************************* -// * called when used as a server, returns whether facility is enabled, this -// * is the whole point of the wormStore - so the answer is true -// **/ -// public boolean preserveSessionData() { -// m_preserveSession = true; -// -// return true; -// } -// -// /******************************************************************************* -// * called by allocation blocks to determine whether they can re-allocate -// * data within this session. -// **/ -// protected boolean isSessionPreserved() { -// return m_preserveSession || m_contexts.size() > 0; -// } - -// /********************************************************************* -// * create backup file, copy data to it, and close it. -// **/ -// synchronized public void backup(String filename) throws FileNotFoundException, IOException { -// File destFile = new File(filename); -// destFile.createNewFile(); -// -// RandomAccessFile dest = new RandomAccessFile(destFile, "rw"); -// -// int bufSize = 64 * 1024; -// byte[] buf = new byte[bufSize]; -// -// m_raf.seek(0); -// -// int rdSize = bufSize; -// while (rdSize == bufSize) { -// rdSize = m_raf.read(buf); -// if (rdSize > 0) { -// dest.write(buf, 0, rdSize); -// } -// } -// -// dest.close(); -// } -// -// /********************************************************************* -// * copy storefile to output stream. -// **/ -// synchronized public void backup(OutputStream outstr) throws IOException { -// int bufSize = 64 * 1024; -// byte[] buf = new byte[bufSize]; -// -// m_raf.seek(0); -// -// int rdSize = bufSize; -// while (rdSize == bufSize) { -// rdSize = m_raf.read(buf); -// if (rdSize > 0) { -// outstr.write(buf, 0, rdSize); -// } -// } -// } -// -// synchronized public void restore(InputStream instr) throws IOException { -// int bufSize = 64 * 1024; -// byte[] buf = new byte[bufSize]; -// -// m_raf.seek(0); -// -// int rdSize = bufSize; -// while (rdSize == bufSize) { -// rdSize = instr.read(buf); -// if (rdSize > 0) { -// m_raf.write(buf, 0, rdSize); -// } -// } -// } - -// /*************************************************************************************** -// * Needed by PSOutputStream for BLOB buffer chaining. -// **/ -// public void absoluteWriteInt(final int addr, final int offset, final int value) { -// try { -// // must check write cache!!, or the write may be overwritten - just -// // flush for now -// m_writes.flush(); -// -// m_raf.seek(physicalAddress(addr) + offset); -// m_raf.writeInt(value); -// } catch (IOException e) { -// throw new StorageTerminalError("Unable to write integer", e); -// } -// } - -// /*************************************************************************************** -// * Needed to free Blob chains. -// **/ -// public int absoluteReadInt(final int addr, final int offset) { -// try { -// m_raf.seek(physicalAddress(addr) + offset); -// return m_raf.readInt(); -// } catch (IOException e) { -// throw new StorageTerminalError("Unable to write integer", e); -// } -// } - -// /*************************************************************************************** -// * Needed by PSOutputStream for BLOB buffer chaining. -// **/ -// public int bufferChainOffset() { -// return m_maxFixedAlloc - 4; -// } - public File getStoreFile() { return m_fd; } -// public boolean isLongAddress() { -// // always ints -// return false; -// } - -// public int absoluteReadLong(long addr, int offset) { -// throw new UnsupportedOperationException(); -// } -// -// public void absoluteWriteLong(long addr, int threshold, long value) { -// throw new UnsupportedOperationException(); -// } - -// public void absoluteWriteAddress(long addr, int threshold, long addr2) { -// absoluteWriteInt((int) addr, threshold, (int) addr2); -// } - -// public int getAddressSize() { -// return 4; -// } - -// public RandomAccessFile getRandomAccessFile() { -// return m_raf; -// } - -// public FileChannel getChannel() { -// return m_raf.getChannel(); -// } - public boolean requiresCommit() { return m_recentAlloc; } @@ -3359,8 +3348,9 @@ /** * Provided with the address of a block of addresses to be freed * @param blockAddr + * @return the total number of addresses freed */ - private void freeDeferrals(final long blockAddr, final long lastReleaseTime) { + private int freeDeferrals(final long blockAddr, final long lastReleaseTime) { final int addr = (int) (blockAddr >> 32); final int sze = (int) blockAddr & 0xFFFFFF; @@ -3371,9 +3361,12 @@ getData(addr, buf); final DataInputStream strBuf = new DataInputStream(new ByteArrayInputStream(buf)); m_allocationLock.lock(); + int totalFreed = 0; try { int nxtAddr = strBuf.readInt(); + int cnt = 0; + while (nxtAddr != 0) { // while (false && addrs-- > 0) { if (nxtAddr > 0) { // Blob @@ -3386,6 +3379,8 @@ immediateFree(nxtAddr, 1); // size ignored for FixedAllocators } + totalFreed++; + nxtAddr = strBuf.readInt(); } m_lastDeferredReleaseTime = lastReleaseTime; @@ -3397,6 +3392,8 @@ } finally { m_allocationLock.unlock(); } + + return totalFreed; } /** @@ -3409,7 +3406,7 @@ * @param toTime * The exclusive upper bound. */ - private void freeDeferrals(final AbstractJournal journal, + private int freeDeferrals(final AbstractJournal journal, final long fromTime, final long toTime) { @@ -3438,6 +3435,8 @@ if(log.isTraceEnabled()) log.trace("fromTime=" + fromTime + ", toTime=" + toTime); + int totalFreed = 0; + while (commitRecords.hasNext()) { final ITuple<CommitRecordIndex.Entry> tuple = commitRecords.next(); @@ -3452,12 +3451,13 @@ if (blockAddr != 0) { - freeDeferrals(blockAddr, record.getTimestamp()); + totalFreed += freeDeferrals(blockAddr, record.getTimestamp()); } } + return totalFreed; } /** @@ -3465,6 +3465,7 @@ * and an overall list of allocators. When the context is detached, all * allocators must be released and any that has available capacity will be * assigned to the global free lists. + * See {@link AllocBlock #releaseSession} * * @param context * The context to be released from all FixedAllocators. @@ -3485,9 +3486,9 @@ /** * The ContextAllocation object manages a freeList of associated allocators - * and an overall list of allocators. When the context is detached, all - * allocators must be released and any that has available capacity will be - * assigned to the global free lists. + * and an overall list of allocators. When the context is aborted then + * allocations made by that context should be released. + * See {@link AllocBlock #abortShadow} * * @param context * The context to be released from all FixedAllocators. @@ -3499,7 +3500,7 @@ final ContextAllocation alloc = m_contexts.remove(context); if (alloc != null) { - alloc.release(); + alloc.abort(); } } finally { m_allocationLock.unlock(); @@ -4352,5 +4353,59 @@ m_allocationLock.unlock(); } } + + /** + * A request for a direct allocation from a Direct ByteBuffer + * + * @param blockSize the size requested + * @return the address of the direct allocation + */ + public int allocateDirect(final int blockSize) { + final int allocBytes = blockSize << this.ALLOCATION_SCALEUP; + if (m_directSpaceAvailable < allocBytes) { + // try and allocate a further buffer + addDirectBuffer(); + } + + if (m_directSpaceAvailable < allocBytes) { + return -1; + } else { + final int ret = m_nextDirectAllocation; + m_nextDirectAllocation += allocBytes; + m_directSpaceAvailable -= allocBytes; + + return ret; + } + } + + /** + * Returns the slot size associated with this address + */ + public int getAssociatedSlotSize(int addr) { + return getBlock(addr).getBlockSize(); + } + + /** + * lockAddress adds the address passed to a lock list. This is for + * debug only and is not intended to be used generally for the live system. + * + * @param addr - address to be locked + */ + public void lockAddress(int addr) { + m_allocationLock.lock(); + try { + if (m_lockAddresses == null) { + m_lockAddresses = new TreeMap<Integer, Integer>(); + } + + if (m_lockAddresses.containsKey(addr)) { + throw new IllegalStateException("address already locked " + addr); + } + + m_lockAddresses.put(addr, addr); + } finally { + m_allocationLock.unlock(); + } + } } Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/StorageStats.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/StorageStats.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/StorageStats.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -207,7 +207,7 @@ return store.divide(size, 2, RoundingMode.HALF_UP).floatValue(); } public float totalWaste(long total) { - if (usedStore() == 0) + if (total == 0) return 0.0f; long slotWaste = reservedStore() - usedStore(); @@ -234,18 +234,30 @@ return allocs.divide(used, 2, RoundingMode.HALF_UP).floatValue(); } public float slotsUnused() { + if (m_totalSlots == 0) { + return 0.0f; + } + BigDecimal used = new BigDecimal(100 * (m_totalSlots-usedSlots())); BigDecimal total = new BigDecimal(m_totalSlots); if(total.signum()==0) return 0f; return used.divide(total, 2, RoundingMode.HALF_UP).floatValue(); } public float percentAllocations(long totalAllocations) { + if (totalAllocations == 0) { + return 0.0f; + } + BigDecimal used = new BigDecimal(100 * m_slotAllocations); BigDecimal total = new BigDecimal(totalAllocations); if(total.signum()==0) return 0f; return used.divide(total, 2, RoundingMode.HALF_UP).floatValue(); } public float percentSlotsInuse(long totalInuse) { + if (totalInuse == 0) { + return 0.0f; + } + BigDecimal used = new BigDecimal(100 * usedSlots()); BigDecimal total = new BigDecimal(totalInuse); if(total.signum()==0) return 0f; @@ -508,6 +520,9 @@ } private float dataPercent(long usedData, long totalData) { + if (totalData == 0) + return 0.0f; + BigDecimal used = new BigDecimal(100 * usedData); BigDecimal total = new BigDecimal(totalData); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java 2010-12-14 17:15:11 UTC (rev 4009) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java 2010-12-16 12:44:43 UTC (rev 4010) @@ -103,6 +103,11 @@ final Journal journal = new Journal(properties); + final IBufferStrategy bufferStrategy = journal.getBufferStrategy(); + if (bufferStrategy instanceof RWStrategy) { + ((RWStrategy)bufferStrategy).getRWStore().activateTx(); + } + try { // if(journal.getBufferStrategy() instanceof MappedBufferStrategy) { @@ -118,7 +123,7 @@ // } doConcurrentClientTest(journal,// - 10,// timeout + 30,// timeout 20,// nresources 1, // minLocks 3, // maxLocks @@ -129,6 +134,9 @@ ); } finally { + if (bufferStrategy instanceof RWStrategy) { + ... [truncated message content] |
From: <mar...@us...> - 2010-12-20 08:57:52
|
Revision: 4023 http://bigdata.svn.sourceforge.net/bigdata/?rev=4023&view=rev Author: martyncutcher Date: 2010-12-20 08:57:44 +0000 (Mon, 20 Dec 2010) Log Message: ----------- fix to AllocBlock releaseSession for higher bit allocations and addition test_stressSessionProtection Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java 2010-12-19 23:36:02 UTC (rev 4022) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/AllocBlock.java 2010-12-20 08:57:44 UTC (rev 4023) @@ -321,11 +321,12 @@ m_transients[i] = m_live[i] | m_commit[i]; chkbits &= ~m_transients[i]; + final int startBit = i * 32; if (chkbits != 0) { // there are writes to clear for (int b = 0; b < 32; b++) { if ((chkbits & (1 << b)) != 0) { - long clr = RWStore.convertAddr(m_addr) + ((long) m_allocator.m_size * b); + long clr = RWStore.convertAddr(m_addr) + ((long) m_allocator.m_size * (startBit + b)); if (log.isTraceEnabled()) log.trace("releasing address: " + clr); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-12-19 23:36:02 UTC (rev 4022) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-12-20 08:57:44 UTC (rev 4023) @@ -20,7 +20,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ + */ /* * Created on Oct 14, 2006 */ @@ -37,6 +37,10 @@ import junit.extensions.proxy.ProxyTestSuite; import junit.framework.Test; +import com.bigdata.btree.IIndex; +import com.bigdata.btree.ITuple; +import com.bigdata.btree.ITupleIterator; +import com.bigdata.btree.IndexMetadata; import com.bigdata.config.LongValidator; import com.bigdata.journal.AbstractInterruptsTestCase; import com.bigdata.journal.AbstractJournalTestCase; @@ -44,7 +48,10 @@ import com.bigdata.journal.AbstractMROWTestCase; import com.bigdata.journal.AbstractRestartSafeTestCase; import com.bigdata.journal.BufferMode; +import com.bigdata.journal.CommitRecordIndex; +import com.bigdata.journal.CommitRecordSerializer; import com.bigdata.journal.DiskOnlyStrategy; +import com.bigdata.journal.ICommitRecord; import com.bigdata.journal.Journal; import com.bigdata.journal.RWStrategy; import com.bigdata.journal.TestJournalBasics; @@ -56,617 +63,623 @@ /** * Test suite for {@link BufferMode#DiskRW} journals. * - * TODO: must modify RWStore to use DirectBufferPool to allocate and release buffers, - * Once done then ensure the write cache is enabled when running test suite + * TODO: must modify RWStore to use DirectBufferPool to allocate and release + * buffers, Once done then ensure the write cache is enabled when running test + * suite * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> * @version $Id$ */ public class TestRWJournal extends AbstractJournalTestCase { - public TestRWJournal() { - super(); - } + public TestRWJournal() { + super(); + } - public TestRWJournal(String name) { - super(name); - } + public TestRWJournal(String name) { + super(name); + } - public static Test suite() { + public static Test suite() { - final TestRWJournal delegate = new TestRWJournal(); // !!!! THIS CLASS !!!! + final TestRWJournal delegate = new TestRWJournal(); // !!!! THIS CLASS + // !!!! - /* - * Use a proxy test suite and specify the delegate. - */ + /* + * Use a proxy test suite and specify the delegate. + */ - final ProxyTestSuite suite = new ProxyTestSuite(delegate, - "Disk RW Journal Test Suite"); + final ProxyTestSuite suite = new ProxyTestSuite(delegate, "Disk RW Journal Test Suite"); - /* - * List any non-proxied tests (typically bootstrapping tests). - */ - - // tests defined by this class. - suite.addTestSuite(TestRWJournal.class); + /* + * List any non-proxied tests (typically bootstrapping tests). + */ - // test suite for the IRawStore api. - suite.addTestSuite(TestRawStore.class); + // tests defined by this class. + suite.addTestSuite(TestRWJournal.class); - // test suite for handling asynchronous close of the file channel. - suite.addTestSuite(TestInterrupts.class); + // test suite for the IRawStore api. + suite.addTestSuite(TestRawStore.class); - // test suite for MROW correctness. - suite.addTestSuite(TestMROW.class); + // test suite for handling asynchronous close of the file channel. + suite.addTestSuite(TestInterrupts.class); - // test suite for MRMW correctness. - suite.addTestSuite(TestMRMW.class); + // test suite for MROW correctness. + suite.addTestSuite(TestMROW.class); - /* - * Pickup the basic journal test suite. This is a proxied test suite, so - * all the tests will run with the configuration specified in this test - * class and its optional .properties file. - */ - suite.addTest(TestJournalBasics.suite()); - - return suite; + // test suite for MRMW correctness. + suite.addTestSuite(TestMRMW.class); - } + /* + * Pickup the basic journal test suite. This is a proxied test suite, so + * all the tests will run with the configuration specified in this test + * class and its optional .properties file. + */ + suite.addTest(TestJournalBasics.suite()); - public Properties getProperties() { + return suite; - final Properties properties = super.getProperties(); + } - properties.setProperty(Options.BUFFER_MODE, BufferMode.DiskRW.toString()); - // properties.setProperty(Options.BUFFER_MODE, BufferMode.TemporaryRW.toString()); + public Properties getProperties() { - // properties.setProperty(Options.CREATE_TEMP_FILE, "true"); - - // properties.setProperty(Options.FILE, "/Volumes/SSDData/TestRW/tmp.rw"); + final Properties properties = super.getProperties(); - properties.setProperty(Options.DELETE_ON_EXIT, "true"); + properties.setProperty(Options.BUFFER_MODE, BufferMode.DiskRW.toString()); + // properties.setProperty(Options.BUFFER_MODE, + // BufferMode.TemporaryRW.toString()); - properties.setProperty(Options.WRITE_CACHE_ENABLED, "" - + writeCacheEnabled); + // properties.setProperty(Options.CREATE_TEMP_FILE, "true"); - // number of bits in FixedAllocators - properties.setProperty(com.bigdata.rwstore.RWStore.Options.DEFAULT_FREE_BITS_THRESHOLD, "1000"); - - // Size of META_BITS_BLOCKS - properties.setProperty(com.bigdata.rwstore.RWStore.Options.DEFAULT_META_BITS_SIZE, "9"); + // properties.setProperty(Options.FILE, + // "/Volumes/SSDData/TestRW/tmp.rw"); - // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32"); // 2K max - properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16"); // 1K + properties.setProperty(Options.DELETE_ON_EXIT, "true"); - // ensure history retention to force deferredFrees - // properties.setProperty(AbstractTransactionService.Options.MIN_RELEASE_AGE, "1"); // Non-zero + properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - return properties; + // number of bits in FixedAllocators + properties.setProperty(com.bigdata.rwstore.RWStore.Options.DEFAULT_FREE_BITS_THRESHOLD, "1000"); - } - - /** - * Verify normal operation and basic assumptions when creating a new journal - * using {@link BufferMode#DiskRW}. - * - * @throws IOException - */ - public void test_create_disk01() throws IOException { + // Size of META_BITS_BLOCKS + properties.setProperty(com.bigdata.rwstore.RWStore.Options.DEFAULT_META_BITS_SIZE, "9"); - File file = null; + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, + // "1,2,3,5,8,12,16,32"); // 2K max + properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16"); // 1K - final Properties properties = getProperties(); + // ensure history retention to force deferredFrees + // properties.setProperty(AbstractTransactionService.Options.MIN_RELEASE_AGE, + // "1"); // Non-zero - final Journal journal = new Journal(properties); + return properties; - try { + } - final RWStrategy bufferStrategy = (RWStrategy) journal - .getBufferStrategy(); + /** + * Verify normal operation and basic assumptions when creating a new journal + * using {@link BufferMode#DiskRW}. + * + * @throws IOException + */ + public void test_create_disk01() throws IOException { - assertTrue("isStable", bufferStrategy.isStable()); - assertFalse("isFullyBuffered", bufferStrategy.isFullyBuffered()); - // assertEquals(Options.FILE, properties.getProperty(Options.FILE), - // bufferStrategy.file.toString()); - assertEquals(Options.INITIAL_EXTENT, Long - .parseLong(Options.DEFAULT_INITIAL_EXTENT), bufferStrategy - .getInitialExtent()); - assertEquals(Options.MAXIMUM_EXTENT, - 0L/* soft limit for disk mode */, bufferStrategy - .getMaximumExtent()); -// assertNotNull("raf", bufferStrategy.getRandomAccessFile()); - assertEquals(Options.BUFFER_MODE, BufferMode.DiskRW, bufferStrategy - .getBufferMode()); + File file = null; - file = journal.getFile(); - - } finally { + final Properties properties = getProperties(); - journal.destroy(); + final Journal journal = new Journal(properties); - } + try { - if(file != null && file.exists()) - fail("Did not delete the backing file: "+file); - - } - - /** - * Unit test verifies that {@link Options#CREATE} may be used to initialize - * a journal on a newly created empty file. - * - * @throws IOException - */ - public void test_create_emptyFile() throws IOException { - - final File file = File.createTempFile(getName(), Options.JNL); + final RWStrategy bufferStrategy = (RWStrategy) journal.getBufferStrategy(); - final Properties properties = new Properties(); + assertTrue("isStable", bufferStrategy.isStable()); + assertFalse("isFullyBuffered", bufferStrategy.isFullyBuffered()); + // assertEquals(Options.FILE, properties.getProperty(Options.FILE), + // bufferStrategy.file.toString()); + assertEquals(Options.INITIAL_EXTENT, Long.parseLong(Options.DEFAULT_INITIAL_EXTENT), bufferStrategy + .getInitialExtent()); + assertEquals(Options.MAXIMUM_EXTENT, 0L/* soft limit for disk mode */, bufferStrategy.getMaximumExtent()); + // assertNotNull("raf", bufferStrategy.getRandomAccessFile()); + assertEquals(Options.BUFFER_MODE, BufferMode.DiskRW, bufferStrategy.getBufferMode()); - properties.setProperty(Options.BUFFER_MODE, BufferMode.DiskRW.toString()); + file = journal.getFile(); - properties.setProperty(Options.FILE, file.toString()); + } finally { - properties.setProperty(Options.WRITE_CACHE_ENABLED, "" - + writeCacheEnabled); + journal.destroy(); - final Journal journal = new Journal(properties); + } - try { + if (file != null && file.exists()) + fail("Did not delete the backing file: " + file); - assertEquals(file, journal.getFile()); + } - } finally { + /** + * Unit test verifies that {@link Options#CREATE} may be used to initialize + * a journal on a newly created empty file. + * + * @throws IOException + */ + public void test_create_emptyFile() throws IOException { - journal.destroy(); + final File file = File.createTempFile(getName(), Options.JNL); - } + final Properties properties = new Properties(); - } + properties.setProperty(Options.BUFFER_MODE, BufferMode.DiskRW.toString()); - /** - * Test suite integration for {@link AbstractRestartSafeTestCase}. - * - * @todo there are several unit tests in this class that deal with - * {@link DiskOnlyStrategy#allocate(int)} and - * {@link DiskOnlyStrategy#update(long, int, ByteBuffer)}. If those - * methods are added to the {@link IRawStore} API then move these unit - * tests into {@link AbstractRawStoreTestCase}. - * - * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - * @version $Id$ - */ - public static class TestRawStore extends AbstractRestartSafeTestCase { - - public TestRawStore() { - super(); - } + properties.setProperty(Options.FILE, file.toString()); - public TestRawStore(String name) { - super(name); - } + properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - protected BufferMode getBufferMode() { - - return BufferMode.DiskRW; - // return BufferMode.TemporaryRW; - - } + final Journal journal = new Journal(properties); - public Properties getProperties() { - - System.out.println("TestRWJournal:getProperties"); + try { - final Properties properties = super.getProperties(); + assertEquals(file, journal.getFile()); - properties.setProperty(Options.BUFFER_MODE, BufferMode.DiskRW.toString()); - // properties.setProperty(Options.BUFFER_MODE, BufferMode.TemporaryRW.toString()); + } finally { - properties.setProperty(Options.CREATE_TEMP_FILE, "true"); - - // properties.setProperty(Options.FILE, "/Volumes/SSDData/TestRW/tmp.rw"); -// properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32,48,64,128,192,320,512,832,1344,2176,3520"); - // properties.setProperty(Options.RW_ALLOCATIONS, "1,2,3,5,8,12,16,32,48,64"); + journal.destroy(); - properties.setProperty(Options.DELETE_ON_EXIT, "true"); + } - properties.setProperty(Options.WRITE_CACHE_ENABLED, "" - + writeCacheEnabled); + } - // number of bits in FixedAllocators - properties.setProperty(RWStore.Options.FREE_BITS_THRESHOLD, "50"); - - // Size of META_BITS_BLOCKS - properties.setProperty(RWStore.Options.META_BITS_SIZE, "9"); + /** + * Test suite integration for {@link AbstractRestartSafeTestCase}. + * + * @todo there are several unit tests in this class that deal with + * {@link DiskOnlyStrategy#allocate(int)} and + * {@link DiskOnlyStrategy#update(long, int, ByteBuffer)}. If those + * methods are added to the {@link IRawStore} API then move these unit + * tests into {@link AbstractRawStoreTestCase}. + * + * @author <a href="mailto:tho...@us...">Bryan + * Thompson</a> + * @version $Id: TestRWJournal.java 4010 2010-12-16 12:44:43Z martyncutcher + * $ + */ + public static class TestRawStore extends AbstractRestartSafeTestCase { - // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32,48,64,128"); // 8K - max blob = 2K * 8K = 16M - // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16,32,48,64,128"); // 2K max - properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16"); // 2K max + public TestRawStore() { + super(); + } - // ensure history retention to force deferredFrees - // properties.setProperty(AbstractTransactionService.Options.MIN_RELEASE_AGE, "1"); // Non-zero + public TestRawStore(String name) { + super(name); + } - return properties; + protected BufferMode getBufferMode() { - } - - protected IRawStore getStore() { - - return new Journal(getProperties()); - - } - -// /** -// * Test that allocate() pre-extends the store when a record is allocated -// * which would overflow the current user extent. -// */ -// public void test_allocPreExtendsStore() { -// -// final Journal store = (Journal) getStore(); -// -// try { -// -// final DiskOnlyStrategy bufferStrategy = (DiskOnlyStrategy) store -// .getBufferStrategy(); -// -// final long nextOffset = store.getRootBlockView() -// .getNextOffset(); -// -// final long length = store.size(); -// -// final long headerSize = FileMetadata.headerSize0; -// -// // #of bytes remaining in the user extent before overflow. -// final long nfree = length - (headerSize + nextOffset); -// -// if (nfree >= Integer.MAX_VALUE) { -// -// /* -// * The test is trying to allocate a single record that will -// * force the store to be extended. This will not work if the -// * store file already has a huge user extent with nothing -// * allocated on it. -// */ -// -// fail("Can't allocate a record with: " + nfree + " bytes"); -// -// } -// -// final int nbytes = (int) nfree; -// -// final long addr = bufferStrategy.allocate(nbytes); -// -// assertNotSame(0L, addr); -// -// assertEquals(nbytes, store.getByteCount(addr)); -// -// // store file was extended. -// assertTrue(store.size() > length); -// -// } finally { -// -// store.destroy(); -// -// } -// -// } + return BufferMode.DiskRW; + // return BufferMode.TemporaryRW; - /** - * Test allocate()+read() where the record was never written (the data - * are undefined unless written so there is nothing really to test here - * except for exceptions which might be through for this condition). - */ - public void test_allocate_then_read() {} + } - /** - * Reallocates the same object several times, then commits and tests read back. - * - * - */ - public void test_reallocate() { - final Journal store = (Journal) getStore(); + public Properties getProperties() { - try { + System.out.println("TestRWJournal:getProperties"); - byte[] buf = new byte[1024]; // 2Mb buffer of random data - r.nextBytes(buf); - - ByteBuffer bb = ByteBuffer.wrap(buf); + final Properties properties = super.getProperties(); - RWStrategy bs = (RWStrategy) store - .getBufferStrategy(); + properties.setProperty(Options.BUFFER_MODE, BufferMode.DiskRW.toString()); + // properties.setProperty(Options.BUFFER_MODE, + // BufferMode.TemporaryRW.toString()); - RWStore rw = bs.getRWStore(); - - long faddr1 = bs.write(bb); - bb.position(0); - //bs.delete(faddr); - - long faddr2 = bs.write(bb); - bb.position(0); - - store.commit(); - - rw.reset(); - - ByteBuffer inbb1 = bs.read(faddr1); - ByteBuffer inbb2 = bs.read(faddr2); - - assertEquals(bb, inbb1); - assertEquals(bb, inbb2); - - } finally { - store.destroy(); - } - - } - - /** - * Test write of a record and then update of a slice of that record. - * <p> - * Note: Since the record was written but not flushed it will be found - * in the write cache by update(). - */ - public void test_write_plus_update() {} - - /** - * Ensures the allocation of unique addresses by mapping allocated address with uniqueness - * assertion against physical address. - */ - public void test_addressing() { - - final Journal store = (Journal) getStore(); + properties.setProperty(Options.CREATE_TEMP_FILE, "true"); - try { + // properties.setProperty(Options.FILE, + // "/Volumes/SSDData/TestRW/tmp.rw"); + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, + // "1,2,3,5,8,12,16,32,48,64,128,192,320,512,832,1344,2176,3520"); + // properties.setProperty(Options.RW_ALLOCATIONS, + // "1,2,3,5,8,12,16,32,48,64"); - RWStrategy bufferStrategy = (RWStrategy) store - .getBufferStrategy(); + properties.setProperty(Options.DELETE_ON_EXIT, "true"); - RWStore rw = bufferStrategy.getRWStore(); - ArrayList<Integer> sizes = new ArrayList<Integer>(); - TreeMap<Long, Integer> paddrs = new TreeMap<Long, Integer>(); - for (int i = 0; i < 100000; i++) { - int s = r.nextInt(250)+1; - sizes.add(s); - int a = rw.alloc(s, null); - long pa = rw.physicalAddress(a); - assertTrue(paddrs.get(pa) == null); - paddrs.put(pa, a); - } - - for (int i = 0; i < 50; i++) { - int s = r.nextInt(500)+1; - sizes.add(s); - int a = rw.alloc(s, null); - long pa = rw.physicalAddress(a); - paddrs.put(pa, a); - } - - } finally { + properties.setProperty(Options.WRITE_CACHE_ENABLED, "" + writeCacheEnabled); - store.destroy(); - - } + // number of bits in FixedAllocators + properties.setProperty(RWStore.Options.FREE_BITS_THRESHOLD, "50"); - - } - - /** - * Basic allocation test to ensure the FixedAllocators are operating efficiently. - * - * A 90 byte allocation is expected to fit in a 128byte block. If we only allocate - * this fixed block size, then we would expect the physical address to increase by 128 bytes - * for each allocation. - */ - public void test_allocations() { - - Journal store = (Journal) getStore(); + // Size of META_BITS_BLOCKS + properties.setProperty(RWStore.Options.META_BITS_SIZE, "9"); - try { + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, + // "1,2,3,5,8,12,16,32,48,64,128"); // 8K - max blob = 2K * 8K = 16M + // properties.setProperty(RWStore.Options.ALLOCATION_SIZES, + // "1,2,3,5,8,12,16,32,48,64,128"); // 2K max + properties.setProperty(RWStore.Options.ALLOCATION_SIZES, "1,2,3,5,8,12,16"); // 2K + // max - RWStrategy bufferStrategy = (RWStrategy) store - .getBufferStrategy(); + // ensure history retention to force deferredFrees + // properties.setProperty(AbstractTransactionService.Options.MIN_RELEASE_AGE, + // "1"); // Non-zero - RWStore rw = bufferStrategy.getRWStore(); - long numAllocs = rw.getTotalAllocations(); - long startAllocations = rw.getTotalAllocationsSize(); - long faddr = allocBatch(rw, 1000, 275, 320); - faddr = allocBatch(rw, 10000, 90, 128); - faddr = allocBatch(rw, 20000, 45, 64); - - System.out.println("Final allocation: " + faddr - + ", allocations: " + (rw.getTotalAllocations() - numAllocs) - + ", allocated bytes: " + (rw.getTotalAllocationsSize() - startAllocations)); - - store.commit(); - - // Confirm that we can re-open the journal after commit - store = (Journal) reopenStore(store); - - } finally { + return properties; - store.destroy(); - - } + } - - } - - /** - * Not so much a test as a code coverage exercise. - * - * The output from showAllocReserve confirms the relative merits of - * optimising for space vs density. The DirectFixedAllocators will - * allocate from DirectBuffers, where locality of reference is less - * important than efficient management of the memory, which is optimised - * by allocations in smaller amounts that match the demands at a finer - * granularity. - */ - public void testAllocationReserves() { - final int cReserve16K = 16 * 1024; - final int cReserve128K = 32 * 1024; - - showAllocReserve(false, 64, cReserve16K, cReserve16K); - showAllocReserve(false, 128, cReserve16K, cReserve16K); - showAllocReserve(false, 1024, cReserve16K, cReserve16K); - showAllocReserve(false, 2048, cReserve16K, cReserve16K); - showAllocReserve(false, 3072, cReserve16K, cReserve16K); - showAllocReserve(false, 4096, cReserve16K, cReserve16K); - showAllocReserve(false, 8192, cReserve16K, cReserve16K); - - showAllocReserve(true, 64, cReserve128K, cReserve16K); - showAllocReserve(true, 128, cReserve128K, cReserve16K); - showAllocReserve(true, 1024, cReserve128K, cReserve16K); - showAllocReserve(true, 2048, cReserve128K, cReserve16K); - showAllocReserve(true, 3072, cReserve128K, cReserve16K); - showAllocReserve(true, 4096, cReserve128K, cReserve16K); - showAllocReserve(true, 8192, cReserve128K, cReserve16K); - } - private void showAllocReserve(final boolean optDensity, final int slotSize, final int reserve, final int mod) { - final int ints = FixedAllocator.calcBitSize(optDensity, slotSize, reserve, mod); - // there are max 254 ints available to a FixedAllocator - final int maxuse = (254/(ints+1)) * ints; - System.out.println("Allocate " + ints + ":" + (32 * ints * slotSize) + " for " + slotSize + " in " + reserve + " using " + maxuse + " of 254 possible"); - } - - long allocBatch(RWStore rw, int bsize, int asze, int ainc) { - long curAddress = rw.physicalAddress(rw.alloc(asze, null)); - for (int i = 1; i < bsize; i++) { - int a = rw.alloc(asze, null); - long nxt = rw.physicalAddress(a); - assertTrue("Problem with index: " + i, diff(curAddress, nxt) == ainc || (nxt % 8192 == 0)); - curAddress = nxt; - } - - return curAddress; - } - - int diff(final long cur, final long nxt) { - int ret = (int) (nxt - cur); - return ret < 0 ? -ret : ret; - } + protected IRawStore getStore() { - int[] allocBatchBuffer(RWStore rw, int bsize, int base, int scope) { - int[] retaddrs = new int[bsize]; - - byte[] batchBuffer = new byte[base+scope]; - r.nextBytes(batchBuffer); - for (int i = 0; i < bsize; i++) { - int as = base + r.nextInt(scope); - retaddrs[i] = (int) rw.alloc(batchBuffer, as, null); - } - - return retaddrs; - } + return new Journal(getProperties()); - - /** - * Reallocation tests the freeing of allocated address and the re-use - * within a transaction. - * - * The repeated runs with full reopening of the store check the - * initialization of the allocators on reload. - * - * @throws IOException - */ - public void test_reallocation() throws IOException { - final Properties properties = getProperties(); - File tmpfile = File.createTempFile("TestRW", "rw"); - properties.setProperty(Options.FILE, tmpfile.getAbsolutePath()); - properties.remove(Options.CREATE_TEMP_FILE); - Journal store = new Journal(properties); + } - try { + // /** + // * Test that allocate() pre-extends the store when a record is + // allocated + // * which would overflow the current user extent. + // */ + // public void test_allocPreExtendsStore() { + // + // final Journal store = (Journal) getStore(); + // + // try { + // + // final DiskOnlyStrategy bufferStrategy = (DiskOnlyStrategy) store + // .getBufferStrategy(); + // + // final long nextOffset = store.getRootBlockView() + // .getNextOffset(); + // + // final long length = store.size(); + // + // final long headerSize = FileMetadata.headerSize0; + // + // // #of bytes remaining in the user extent before overflow. + // final long nfree = length - (headerSize + nextOffset); + // + // if (nfree >= Integer.MAX_VALUE) { + // + // /* + // * The test is trying to allocate a single record that will + // * force the store to be extended. This will not work if the + // * store file already has a huge user extent with nothing + // * allocated on it. + // */ + // + // fail("Can't allocate a record with: " + nfree + " bytes"); + // + // } + // + // final int nbytes = (int) nfree; + // + // final long addr = bufferStrategy.allocate(nbytes); + // + // assertNotSame(0L, addr); + // + // assertEquals(nbytes, store.getByteCount(addr)); + // + // // store file was extended. + // assertTrue(store.size() > length); + // + // } finally { + // + // store.destroy(); + // + // } + // + // } - RWStrategy bufferStrategy = (RWStrategy) store - .getBufferStrategy(); + /** + * Test allocate()+read() where the record was never written (the data + * are undefined unless written so there is nothing really to test here + * except for exceptions which might be through for this condition). + */ + public void test_allocate_then_read() { + } - RWStore rw = bufferStrategy.getRWStore(); - long numAllocs = rw.getTotalAllocations(); - long startAllocations = rw.getTotalAllocationsSize(); - - reallocBatch(rw, 1000, 275, 1000); - - store.commit(); - store.close(); - store = new Journal(properties); - bufferStrategy = (RWStrategy) store.getBufferStrategy(); - rw = bufferStrategy.getRWStore(); - - reallocBatch(rw, 1000, 100, 10000); - - store.commit(); - store.close(); - store = new Journal(properties); - bufferStrategy = (RWStrategy) store.getBufferStrategy(); - rw = bufferStrategy.getRWStore(); + /** + * Reallocates the same object several times, then commits and tests + * read back. + * + * + */ + public void test_reallocate() { + final Journal store = (Journal) getStore(); - reallocBatch(rw, 1000, 100, 10000); - - store.commit(); - store.close(); - store = new Journal(properties); - bufferStrategy = (RWStrategy) store.getBufferStrategy(); - rw = bufferStrategy.getRWStore(); + try { - System.out.println("Final allocations: " + (rw.getTotalAllocations() - numAllocs) - + ", allocated bytes: " + (rw.getTotalAllocationsSize() - startAllocations) - + ", file length: " + rw.getStoreFile().length()); - } finally { + byte[] buf = new byte[1024]; // 2Mb buffer of random data + r.nextBytes(buf); - store.destroy(); - - } + ByteBuffer bb = ByteBuffer.wrap(buf); - - } + RWStrategy bs = (RWStrategy) store.getBufferStrategy(); - private long reallocBatch(RWStore rw, int tsts, int sze, int grp) { - long[] addr = new long[grp]; - for (int i = 0; i < grp; i++) { - addr[i] = rw.alloc(2 + r.nextInt(sze), null); - } - for (int t = 0; t < tsts; t++) { - for (int i = 0; i < grp; i++) { - long old = addr[i]; - int asze = 2 + r.nextInt(sze); - addr[i] = rw.alloc(asze, null); - - if (i % 2 == 0) - rw.free(old, 1); // dunno what the real size is - } - } - - return 0L; + RWStore rw = bs.getRWStore(); + + long faddr1 = bs.write(bb); + bb.position(0); + // bs.delete(faddr); + + long faddr2 = bs.write(bb); + bb.position(0); + + store.commit(); + + rw.reset(); + + ByteBuffer inbb1 = bs.read(faddr1); + ByteBuffer inbb2 = bs.read(faddr2); + + assertEquals(bb, inbb1); + assertEquals(bb, inbb2); + + } finally { + store.destroy(); + } + } - - public void test_reallocationWithReadAndReopen() { - - Journal store = (Journal) getStore(); - try { + /** + * Test write of a record and then update of a slice of that record. + * <p> + * Note: Since the record was written but not flushed it will be found + * in the write cache by update(). + */ + public void test_write_plus_update() { + } + /** + * Ensures the allocation of unique addresses by mapping allocated + * address with uniqueness assertion against physical address. + */ + public void test_addressing() { + + final Journal store = (Journal) getStore(); + + try { + RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); RWStore rw = bufferStrategy.getRWStore(); - + ArrayList<Integer> sizes = new ArrayList<Integer>(); + TreeMap<Long, Integer> paddrs = new TreeMap<Long, Integer>(); + for (int i = 0; i < 100000; i++) { + int s = r.nextInt(250) + 1; + sizes.add(s); + int a = rw.alloc(s, null); + long pa = rw.physicalAddress(a); + assertTrue(paddrs.get(pa) == null); + paddrs.put(pa, a); + } + + for (int i = 0; i < 50; i++) { + int s = r.nextInt(500) + 1; + sizes.add(s); + int a = rw.alloc(s, null); + long pa = rw.physicalAddress(a); + paddrs.put(pa, a); + } + + } finally { + + store.destroy(); + + } + + } + + /** + * Basic allocation test to ensure the FixedAllocators are operating + * efficiently. + * + * A 90 byte allocation is expected to fit in a 128byte block. If we + * only allocate this fixed block size, then we would expect the + * physical address to increase by 128 bytes for each allocation. + */ + public void test_allocations() { + + Journal store = (Journal) getStore(); + + try { + + RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); + + RWStore rw = bufferStrategy.getRWStore(); + long numAllocs = rw.getTotalAllocations(); + long startAllocations = rw.getTotalAllocationsSize(); + long faddr = allocBatch(rw, 1000, 275, 320); + faddr = allocBatch(rw, 10000, 90, 128); + faddr = allocBatch(rw, 20000, 45, 64); + + System.out.println("Final allocation: " + faddr + ", allocations: " + + (rw.getTotalAllocations() - numAllocs) + ", allocated bytes: " + + (rw.getTotalAllocationsSize() - startAllocations)); + + store.commit(); + + // Confirm that we can re-open the journal after commit + store = (Journal) reopenStore(store); + + } finally { + + store.destroy(); + + } + + } + + /** + * Not so much a test as a code coverage exercise. + * + * The output from showAllocReserve confirms the relative merits of + * optimising for space vs density. The DirectFixedAllocators will + * allocate from DirectBuffers, where locality of reference is less + * important than efficient management of the memory, which is optimised + * by allocations in smaller amounts that match the demands at a finer + * granularity. + */ + public void testAllocationReserves() { + final int cReserve16K = 16 * 1024; + final int cReserve128K = 32 * 1024; + + showAllocReserve(false, 64, cReserve16K, cReserve16K); + showAllocReserve(false, 128, cReserve16K, cReserve16K); + showAllocReserve(false, 1024, cReserve16K, cReserve16K); + showAllocReserve(false, 2048, cReserve16K, cReserve16K); + showAllocReserve(false, 3072, cReserve16K, cReserve16K); + showAllocReserve(false, 4096, cReserve16K, cReserve16K); + showAllocReserve(false, 8192, cReserve16K, cReserve16K); + + showAllocReserve(true, 64, cReserve128K, cReserve16K); + showAllocReserve(true, 128, cReserve128K, cReserve16K); + showAllocReserve(true, 1024, cReserve128K, cReserve16K); + showAllocReserve(true, 2048, cReserve128K, cReserve16K); + showAllocReserve(true, 3072, cReserve128K, cReserve16K); + showAllocReserve(true, 4096, cReserve128K, cReserve16K); + showAllocReserve(true, 8192, cReserve128K, cReserve16K); + } + + private void showAllocReserve(final boolean optDensity, final int slotSize, final int reserve, final int mod) { + final int ints = FixedAllocator.calcBitSize(optDensity, slotSize, reserve, mod); + // there are max 254 ints available to a FixedAllocator + final int maxuse = (254 / (ints + 1)) * ints; + System.out.println("Allocate " + ints + ":" + (32 * ints * slotSize) + " for " + slotSize + " in " + + reserve + " using " + maxuse + " of 254 possible"); + } + + long allocBatch(RWStore rw, int bsize, int asze, int ainc) { + long curAddress = rw.physicalAddress(rw.alloc(asze, null)); + for (int i = 1; i < bsize; i++) { + int a = rw.alloc(asze, null); + long nxt = rw.physicalAddress(a); + assertTrue("Problem with index: " + i, diff(curAddress, nxt) == ainc || (nxt % 8192 == 0)); + curAddress = nxt; + } + + return curAddress; + } + + int diff(final long cur, final long nxt) { + int ret = (int) (nxt - cur); + return ret < 0 ? -ret : ret; + } + + int[] allocBatchBuffer(RWStore rw, int bsize, int base, int scope) { + int[] retaddrs = new int[bsize]; + + byte[] batchBuffer = new byte[base + scope]; + r.nextBytes(batchBuffer); + for (int i = 0; i < bsize; i++) { + int as = base + r.nextInt(scope); + retaddrs[i] = (int) rw.alloc(batchBuffer, as, null); + } + + return retaddrs; + } + + /** + * Reallocation tests the freeing of allocated address and the re-use + * within a transaction. + * + * The repeated runs with full reopening of the store check the + * initialization of the allocators on reload. + * + * @throws IOException + */ + public void test_reallocation() throws IOException { + final Properties properties = getProperties(); + File tmpfile = File.createTempFile("TestRW", "rw"); + properties.setProperty(Options.FILE, tmpfile.getAbsolutePath()); + properties.remove(Options.CREATE_TEMP_FILE); + Journal store = new Journal(properties); + + try { + + RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); + + RWStore rw = bufferStrategy.getRWStore(); + long numAllocs = rw.getTotalAllocations(); + long startAllocations = rw.getTotalAllocationsSize(); + + reallocBatch(rw, 1000, 275, 1000); + + store.commit(); + store.close(); + store = new Journal(properties); + bufferStrategy = (RWStrategy) store.getBufferStrategy(); + rw = bufferStrategy.getRWStore(); + + reallocBatch(rw, 1000, 100, 10000); + + store.commit(); + store.close(); + store = new Journal(properties); + bufferStrategy = (RWStrategy) store.getBufferStrategy(); + rw = bufferStrategy.getRWStore(); + + reallocBatch(rw, 1000, 100, 10000); + + store.commit(); + store.close(); + store = new Journal(properties); + bufferStrategy = (RWStrategy) store.getBufferStrategy(); + rw = bufferStrategy.getRWStore(); + + System.out.println("Final allocations: " + (rw.getTotalAllocations() - numAllocs) + + ", allocated bytes: " + (rw.getTotalAllocationsSize() - startAllocations) + ", file length: " + + rw.getStoreFile().length()); + } finally { + + store.destroy(); + + } + + } + + private long reallocBatch(RWStore rw, int tsts, int sze, int grp) { + long[] addr = new long[grp]; + for (int i = 0; i < grp; i++) { + addr[i] = rw.alloc(2 + r.nextInt(sze), null); + } + for (int t = 0; t < tsts; t++) { + for (int i = 0; i < grp; i++) { + long old = addr[i]; + int asze = 2 + r.nextInt(sze); + addr[i] = rw.alloc(asze, null); + + if (i % 2 == 0) + rw.free(old, 1); // dunno what the real size is + } + } + + return 0L; + } + + public void test_reallocationWithReadAndReopen() { + + Journal store = (Journal) getStore(); + + try { + + RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); + + RWStore rw = bufferStrategy.getRWStore(); + final int tcount = 2000; // increase to ramp up stress levels long numAllocs = rw.getTotalAllocations(); long startAllocations = rw.getTotalAllocationsSize(); // reallocBatchWithRead(bufferStrategy, 100000, 275, 5); - reallocBatchWithRead(store, 1, 100, 250, tcount, true, true); + reallocBatchWithRead(store, 1, 100, 250, tcount, true, true); store.close(); - + // added to try and foce bug System.out.println("Re-open Journal"); store = (Journal) getStore(); reallocBatchWithRead(store, 1, 800, 1500, tcount, true, true); reallocBatchWithRead(store, 1, 50, 250, tcount, true, true); - reallocBatchWithRead(store, 1, 50, 250, tcount, true, true); + reallocBatchWithRead(store, 1, 50, 250, tcount, true, true); store.close(); // .. end add to force bug - + System.out.println("Re-open Journal"); store = (Journal) getStore(); reallocBatchWithRead(store, 1, 2000, 10000, tcount, true, true); @@ -676,7 +689,7 @@ store = (Journal) getStore(); reallocBatchWithRead(store, 1, 800, 1256, tcount, true, true); reallocBatchWithRead(store, 1, 50, 250, tcount, true, true); - reallocBatchWithRead(store, 1, 50, 250, tcount, true, true); + reallocBatchWithRead(store, 1, 50, 250, tcount, true, true); showStore(store); store.close(); System.out.println("Re-open Journal"); @@ -699,88 +712,87 @@ } finally { store.destroy(); - - } - - } - - void showStore(Journal store) { - RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); + } + } + + void showStore(Journal store) { + RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); + RWStore rw = bufferStrategy.getRWStore(); - System.out.println("Fixed Allocators: " + rw.getFixedAllocatorCount() - + ", heap allocated: " + rw.getFileStorage() - + ", utilised bytes: " + rw.getAllocatedSlots() - + ", file length: " + rw.getStoreFile().length()); + System.out.println("Fixed Allocators: " + rw.getFixedAllocatorCount() + ", heap allocated: " + + rw.getFileStorage() + ", utilised bytes: " + rw.getAllocatedSlots() + ", file length: " + + rw.getStoreFile().length()); - } - - // Only realloc 1/5 - byte allocChar = 0; - private long reallocBatchWithRead(Journal store, int tsts, int min, int sze, int grp, boolean commit, boolean reopen) { - allocChar = (byte) (allocChar+1); - - RWStrategy bs = (RWStrategy) store - .getBufferStrategy(); + } - byte[] buf = new byte[sze+4]; // extra for checksum - // r.nextBytes(buf); - for (int i = 0; i < buf.length; i++) { - buf[i] = allocChar; - } - - - RWStore rw = bs.getRWStore(); - - long[] addr = new long[grp/5]; - int[] szes = new int[grp]; - for (int i = 0; i < grp; i++) { - szes[i] = min + r.nextInt(sze-min); - ByteBuffer bb = ByteBuffer.wrap(buf, 0, szes[i]); - if (i % 5 == 0) - addr[i/5] = bs.write(bb); - } - - if (commit) { - store.commit(); - } - - for (int t = 0; t < tsts; t++) { - for (int i = 0; i < (grp/5); i++) { - long old = addr[i]; - try { - bs.read(old); - } catch (Exception e) { - throw new RuntimeException("problem handling read: " + i + " in test: " + t + " from address: " + old, e); - } - ByteBuffer bb = ByteBuffer.wrap(buf, 0, szes[i]); - addr[i] = bs.write(bb); - bb.flip(); - bs.delete(old); - } - } - - if (commit) { - store.commit(); - - if (reopen) - rw.reset(); - - } - return 0L; + // Only realloc 1/5 + byte allocChar = 0; + + private long reallocBatchWithRead(Journal store, int tsts, int min, int sze, int grp, boolean commit, + boolean reopen) { + allocChar = (byte) (allocChar + 1); + + RWStrategy bs = (RWStrategy) store.getBufferStrategy(); + + byte[] buf = new byte[sze + 4]; // extra for checksum + // r.nextBytes(buf); + for (int i = 0; i < buf.length; i++) { + buf[i] = allocChar; + } + + RWStore rw = bs.getRWStore(); + + long[] addr = new long[grp / 5]; + int[] szes = new int[grp]; + for (int i = 0; i < grp; i++) { + szes[i] = min + r.nextInt(sze - min); + ByteBuffer bb = ByteBuffer.wrap(buf, 0, szes[i]); + if (i % 5 == 0) + addr[i / 5] = bs.write(bb); + } + + if (commit) { + store.commit(); + } + + for (int t = 0; t < tsts; t++) { + for (int i = 0; i < (grp / 5); i++) { + long old = addr[i]; + try { + bs.read(old); + } catch (Exception e) { + throw new RuntimeException("problem handling read: " + i + " in test: " + t + " from address: " + + old, e); + } + ByteBuffer bb = ByteBuffer.wrap(buf, 0, szes[i]); + addr[i] = bs.write(bb); + bb.flip(); + bs.delete(old); + } + } + + if (commit) { + store.commit(); + + if (reopen) + rw.reset(); + + } + return 0L; } - /** - * Adjust tcount to increase stress levels - */ - public void test_stressReallocationWithRead() { - - Journal store = (Journal) getStore(); + /** + * Adjust tcount to increase stress levels + */ + public void test_stressReallocationWithRead() { - try { + Journal store = (Journal) getStore(); + try { + final int tcount = 2000; // increase to ramp up stress levels RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); @@ -790,16 +802,16 @@ long numAllocs = rw.getTotalAllocations(); long startAllocations = rw.getTotalAllocationsSize(); // reallocBatchWithRead(bufferStrategy, 100000, 275, 5); - reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); - - reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); - reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); + reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); + reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); + reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); + reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); reallocBatchWithRead(store, 1, 800, 1500, tcount, false, false); reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); - reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); + reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); // Extend file with sizeable allocations reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); @@ -807,14 +819,14 @@ reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); - + reallocBatchWithRead(store, 1, 250, 500, tcount, false, false); reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); reallocBatchWithRead(store, 1, 800, 1256, tcount, false, false); reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); - reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); + reallocBatchWithRead(store, 1, 50, 250, tcount, false, false); reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); @@ -829,296 +841,295 @@ reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); reallocBatchWithRead(store, 1, 5000, 10000, tcount, false, false); - + reallocBatchWithRead(store, 1, 500, 1000, tcount, false, false); reallocBatchWithRead(store, 1, 1000, 2000, tcount, false, false); reallocBatchWithRead(store, 1, 500, 1000, tcount, false, false); - + store.commit(); - + showStore(store); - + store.close(); - + store = (Journal) getStore(); showStore(store); } finally { store.destroy(); - - } - - } + } - /** - * Test of blob allocation, does not check on read back, just the allocation - */ - public void test_blob_allocs() { - if (false) { - return; - } - - final Journal store = (Journal) getStore(); + } - try { + /** + * Test of blob allocation, does not check on read back, just the + * allocation + */ + public void test_blob_allocs() { + if (false) { + return; + } - RWStrategy bufferStrategy = (RWStrategy) store - .getBufferStrategy(); + final Journal store = (Journal) getStore(); - RWStore rw = bufferStrategy.getRWStore(); - long numAllocs = rw.getTotalAllocations(); - long startAllocations = rw.getTotalAllocationsSize(); - int startBlob = 1024 * 256; - int endBlob = 1024 * 1256; - int[] faddrs = allocBatchBuffer(rw, 100, startBlob, endBlob); - + try { + + RWStrategy bufferStrategy = (RWStrategy) store.getBufferStrategy(); + + RWStore rw = bufferStrategy.getRWStore(); + long numAllocs = rw.getTotalAllocations(); + long startAllocations = rw.getTotalAllocationsSize(); + int startBlob = 1024 * 256; + int endBlob = 1024 * 1256; + int[] faddrs = allocBatchBuffer(rw, 100, startBlob, endBlob); + final StringBuilder str = new StringBuilder(); rw.getStorageStats().showStats(str); - System.out.println(str); - } finally { + System.out.println(str); + } finally { - store.destroy(); - - } - - } - /** - * Test of blob allocation and read-back, firstly from cache and then from disk. - */ - public void test_blob_readBack() { - - final Journal store = (Journal) getStore(); + store.destroy(); - try { - final RWStrategy bs = (RWStrategy) store - .getBufferStrategy(); + } - final RWStore rw = bs.getRWStore(); - + } - byte[] buf = new byte[2 * 1024 * 1024]; // 5Mb buffer of random data - r.nextBytes(buf); - - ByteBuffer bb = ByteBuffer.wrap(buf); + /** + * Test of blob allocation and read-back, firstly from cache and then + * from disk. + */ + public void test_blob_readBack() { - long faddr = bs.write(bb); // rw.alloc(buf, buf.length); - - log.info("Blob Allocation at " + rw.convertFromAddr(faddr)); - - bb.position(0); - - ByteBuffer rdBuf = bs.read(faddr); - - assertEquals(bb, rdBuf); - - System.out.println("Now commit to disk"); - - store.commit(); - - // Now reset - clears writeCache and reinits from disk - rw.reset(); - - rdBuf = bs.read(faddr); - assertEquals(bb, rdBuf); + final Journal store = (Journal) getStore(); - } finally { + try { + final RWStrategy bs = (RWStrategy) store.getBufferStrategy(); - store.destroy(); - - } - - } - - /** - * Test of blob allocation and read-back, firstly from cache and then from disk. - * @throws InterruptedException - */ - public void test_blob_realloc() throws InterruptedException { - - final Journal store = (Journal) getStore(); + final RWStore rw = bs.getRWStore(); - try { + byte[] buf = new byte[2 * 1024 * 1024]; // 5Mb buffer of random + // data + r.nextBytes(buf); - final byte[] buf = new byte[1024 * 2048]; // 2Mb buffer of random data - r.nextBytes(buf); - - final ByteBuffer bb = ByteBuffer.wrap(buf); + ByteBuffer bb = ByteBuffer.wrap(buf); - final RWStrategy bs = (RWStrategy) store - .getBufferStrategy(); + long faddr = bs.write(bb); // rw.alloc(buf, buf.length); - final RWStore rw = bs.getRWStore(); - - long faddr = bs.write(bb); // rw.alloc(buf, buf.length); - - bb.position(0); - - ByteBuffer rdBuf = bs.read(faddr); - - assertEquals(bb, rdBuf); - - // now delete the memory - bs.delete(faddr); - - // verify immediateFree! - assertEquals(0L,bs.getPhysicalAddress(faddr)); - - // allocate another address, might (or might not) be the same. - faddr = bs.write(bb); // rw.alloc(buf, buf.length); - final long pa = bs.getPhysicalAddress(faddr); - bb.position(0); - - System.out.println("Now commit to disk (1)"); - - store.commit(); - - // Now reset - clears writeCache and reinits from disk - rw.reset(); - - rdBuf = bs.read(faddr); - assertEquals(bb, rdBuf); + log.info("Blob Allocation at " + rw.convertFromAddr(faddr)); - // now delete the memory - bs.delete(faddr); + bb.position(0); - // Must not have been immediately freed if history is retained. - if (rw.getHistoryRetention() != 0) - assertEquals(pa, bs.getPhysicalAddress(faddr)); - else - assertEquals(0L, bs.getPhysicalAddress(faddr)); - + ByteBuffer rdBuf = bs.read(faddr); - /* - * Commit before testing for deferred frees. Since there is a - * prior commit point, we are not allowed to immediately free - * any record from that commit point in order to preserve the - * consistency of the last commit point, so we have to commit - * first then test for deferred frees. - */ - System.out.println("Now commit to disk (2)"); - - store.commit(); - - Thread.currentThread().sleep(10); - - // Request release of deferred frees. - rw.checkDeferredFrees(true/* freeNow */, store); + assertEquals(bb, rdBuf); - assertEquals(0L, bs.getPhysicalAddress(faddr)); + System.out.println("Now commit to disk"); - try { - rdBuf = bs.read(faddr); // should fail with illegal argument - throw new RuntimeException("Fail"); - } catch (Exception ise) { - assertTrue("Expected IllegalArgumentException reading from " + (faddr >> 32) + " instead got: " + ise, ise instanceof IllegalArgumentException); - } - - } finally { + store.commit(); - store.destroy(); - - } - - } + // Now reset - clears writeCache and reinits from disk + rw.reset(); - + rdBuf = bs.read(faddr); + assertEquals(bb, rdBuf); + + } finally { + + store.destroy(); + + } + + } + /** - * Ttest write() + flush() + update() - for this case the data have been - * flushed from the write cache so the update will be a random write on - * the file rather than being buffered by the write cache. - */ - public void test_write_flush_update() { - - final Journal store = (Journal) getStore(); + * Test of blob allocation and read-back, firstly from cache and then + * from disk. + * + * @throws InterruptedException + */ + public void test_blob_realloc() throws InterruptedException { - try { + final Journal store = (Journal) getStore(); - RWStrategy bufferStrategy = (RWStrategy) store - .getBufferStrategy(); + try { - final int nbytes = 60; + final byte[] buf = new byte[1024 * 2048]; // 2Mb buffer of + // random data + r.nextBytes(buf); - // random data. - byte[] a = new byte[nbytes]; - r.nextBytes(a); - - // write a new record. - final long addr = bufferStrategy.write(ByteBuffer.wrap(a)); + final ByteBuffer bb = ByteBuffer.wrap(buf); - assertEquals(nbytes, store.getByteCount(addr)); - - // Note: This will result flush the write cache. - store.commit(); - - /* - * Read back the record and verify the update is visible. - */ - { - - final ByteBuffer b = bufferStrategy.read(addr); - - assertNotNull(b); - - for(int i=20; i<40; i++) { - - assertEquals("data differs at offset=" + i, a[i], b - .get(i)); - - } - - } - - } finally { + final RWStrategy bs = (RWStrategy) store.getBufferStrategy(); - store.destroy(); - - } + final RWStore rw = bs.getRWStore(); - } + long faddr = bs.write(bb); // rw.alloc(buf, buf.length); - public void test_metaAlloc() { - - Journal store = (Journal) getStore(); + bb.position(... [truncated message content] |
From: <mar...@us...> - 2010-12-20 12:06:14
|
Revision: 4024 http://bigdata.svn.sourceforge.net/bigdata/?rev=4024&view=rev Author: martyncutcher Date: 2010-12-20 12:06:07 +0000 (Mon, 20 Dec 2010) Log Message: ----------- Ensure deletions trigger RWStore commit required, and remove unnecessary transaction bracketing from concurrency tests. Modified Paths: -------------- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-12-20 08:57:44 UTC (rev 4023) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2010-12-20 12:06:07 UTC (rev 4024) @@ -1589,7 +1589,7 @@ * FIXME We need unit test when MIN_RELEASE_AGE is ZERO AND * there are open read-only transactions. */ - if (false&&m_minReleaseAge == 0) { + if (m_minReleaseAge == 0) { /* * The session protection is complicated by the mix of * transaction protection and isolated AllocationContexts. @@ -1737,6 +1737,8 @@ if (!m_commitList.contains(alloc)) { m_commitList.add(alloc); + + m_recentAlloc = true; } } finally { m_allocationLock.unlock(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java 2010-12-20 08:57:44 UTC (rev 4023) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/StressTestConcurrentUnisolatedIndices.java 2010-12-20 12:06:07 UTC (rev 4024) @@ -103,10 +103,10 @@ final Journal journal = new Journal(properties); - final IBufferStrategy bufferStrategy = journal.getBufferStrategy(); - if (bufferStrategy instanceof RWStrategy) { - ((RWStrategy)bufferStrategy).getRWStore().activateTx(); - } +// final IBufferStrategy bufferStrategy = journal.getBufferStrategy(); +// if (bufferStrategy instanceof RWStrategy) { +// ((RWStrategy)bufferStrategy).getRWStore().activateTx(); +// } try { @@ -134,9 +134,9 @@ ); } finally { - if (bufferStrategy instanceof RWStrategy) { - ((RWStrategy)bufferStrategy).getRWStore().deactivateTx(); - } +// if (bufferStrategy instanceof RWStrategy) { +// ((RWStrategy)bufferStrategy).getRWStore().deactivateTx(); +// } journal.destroy(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java 2010-12-20 08:57:44 UTC (rev 4023) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/journal/TestConcurrentJournal.java 2010-12-20 12:06:07 UTC (rev 4024) @@ -1653,10 +1653,10 @@ properties.setProperty(Options.WRITE_SERVICE_MAXIMUM_POOL_SIZE, "1"); final Journal journal = new Journal(properties); - final IBufferStrategy bufferStrategy = journal.getBufferStrategy(); - if (bufferStrategy instanceof RWStrategy) { - ((RWStrategy)bufferStrategy).getRWStore().activateTx(); - } +// final IBufferStrategy bufferStrategy = journal.getBufferStrategy(); +// if (bufferStrategy instanceof RWStrategy) { +// ((RWStrategy)bufferStrategy).getRWStore().activateTx(); +// } try { @@ -1805,9 +1805,9 @@ } finally { - if (bufferStrategy instanceof RWStrategy) { - ((RWStrategy)bufferStrategy).getRWStore().deactivateTx(); - } +// if (bufferStrategy instanceof RWStrategy) { +// ((RWStrategy)bufferStrategy).getRWStore().deactivateTx(); +// } journal.destroy(); Modified: branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java =================================================================== --- branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-12-20 08:57:44 UTC (rev 4023) +++ branches/JOURNAL_HA_BRANCH/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java 2010-12-20 12:06:07 UTC (rev 4024) @@ -997,26 +997,35 @@ bs.delete(faddr); // Must not have been immediately freed if history is retained. - if (rw.getHistoryRetention() != 0) + if (rw.getHistoryRetention() != 0) { assertEquals(pa, bs.getPhysicalAddress(faddr)); - else - assertEquals(0L, bs.getPhysicalAddress(faddr)); - /* - * Commit before testing for deferred frees. Since there is a - * prior commit point, we are not allowed to immediately free - * any record from that commit point in order to preserve the - * consistency of the last commit point, so we have to commit - * first then test for deferred frees. - */ - System.out.println("Now commit to disk (2)"); + /* + * Commit before testing for deferred frees. Since there is a + * prior commit point, we are not allowed to immediately free + * any record from that commit point in order to preserve the + * consistency of the last commit point, so we have to commit + * first then test for deferred frees. + */ + System.out.println("Now commit to disk (2)"); - store.commit(); + store.commit(); - Thread.currentThread().sleep(10); + Thread.currentThread().sleep(10); // to force deferredFrees - // Request release of deferred frees. - rw.checkDeferredFrees(true/* freeNow */, store); + // Request release of deferred frees. + rw.checkDeferredFrees(true/* freeNow */, store); + + // Now commit() to ensure the deferrals can be recycled + store.commit(); + } else { + // The address is deleted, but will still return a valid + // address since it is committed + assertEquals(pa, bs.getPhysicalAddress(faddr)); + + // Now commit() to ensure the deferrals can be recycled + store.commit(); + } assertEquals(0L, bs.getPhysicalAddress(faddr)); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |