From: <mar...@us...> - 2013-01-23 14:21:23
|
Revision: 6818 http://bigdata.svn.sourceforge.net/bigdata/?rev=6818&view=rev Author: martyncutcher Date: 2013-01-23 14:21:12 +0000 (Wed, 23 Jan 2013) Log Message: ----------- sync prior to review Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WriteExecutorService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -34,6 +34,7 @@ import java.security.DigestException; import java.security.MessageDigest; import java.util.Formatter; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; @@ -162,7 +163,7 @@ // protected by m_writeLock private long m_writePosition = -1; - private int m_sequence = 0; + private AtomicLong m_sequence = new AtomicLong(0); /** * This constructor is called by the log manager to create the file. A @@ -340,7 +341,7 @@ + m_openRootBlock.getLastCommitTime() + ", but msg=" + msg); - if (m_sequence != msg.getSequence()) + if (m_sequence.get() != msg.getSequence()) throw new IllegalStateException("nextSequence=" + m_sequence + ", but msg=" + msg); @@ -391,7 +392,7 @@ throw new AssertionError(); } - m_sequence++; + m_sequence.incrementAndGet(); m_fileChange.signalAll(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -2446,51 +2446,30 @@ /* * Take the buffer from the cleanList and set it has the * [current] buffer. - * - * Note: We use the [cleanListNotEmpty] Condition so we can - * notice a [halt]. */ - cleanListLock.lockInterruptibly(); + + // Grab buffer from clean list. + final WriteCache newBuffer = takeFromClean(); + + counters.get().nclean--; + // Clear the state on the new buffer and remove from + // cacheService map + newBuffer.resetWith(serviceMap);//, fileExtent.get()); - try { + // Set it as the new buffer. + current.set(cache = newBuffer); - if (log.isInfoEnabled() && cleanList.isEmpty()) - log.info("Waiting for clean buffer"); - - while (cleanList.isEmpty() && !halt) { - cleanListNotEmpty.await(); - } + // Try to write on the new buffer. + if (cache.write(offset, data, chk, useChecksum, latchedAddr)) { - if (halt) - throw new RuntimeException(firstCause.get()); - - // Take a buffer from the cleanList (guaranteed avail). - final WriteCache newBuffer = cleanList.take(); - counters.get().nclean--; - // Clear the state on the new buffer and remove from - // cacheService map - newBuffer.resetWith(serviceMap);//, fileExtent.get()); - - // Set it as the new buffer. - current.set(cache = newBuffer); - - // Try to write on the new buffer. - if (cache.write(offset, data, chk, useChecksum, latchedAddr)) { - - // This must be the only occurrence of this record. - if (serviceMap.put(offset, cache) != null) { - throw new AssertionError("Record already in cache: offset=" + offset + " " + addrDebugInfo(offset)); - } - - - return true; - + // This must be the only occurrence of this record. + if (serviceMap.put(offset, cache) != null) { + throw new AssertionError("Record already in cache: offset=" + offset + " " + addrDebugInfo(offset)); } - } finally { + + return true; - cleanListLock.unlock(); - } /* @@ -2513,7 +2492,44 @@ } } + + private WriteCache takeFromClean() throws InterruptedException { + cleanListLock.lockInterruptibly(); + try { + + while (true) { + + if (log.isInfoEnabled() && cleanList.isEmpty()) + log.info("Waiting for clean buffer"); + + /* + * Note: We use the [cleanListNotEmpty] Condition so we can + * notice a [halt]. + */ + while (cleanList.isEmpty() && !halt) { + cleanListNotEmpty.await(); + } + + if (halt) + throw new RuntimeException(firstCause.get()); + + // Poll() rather than take() since other methods poll() the list + // unprotected. + final WriteCache ret = cleanList.poll(); + + if (ret != null) { + return ret; + } + + } + + } finally { + cleanListLock.unlock(); + } + } + + // /** // * Caches data read from disk (or even read from "older" cache). // * The assumption is that we do not need a "reserve" buffer. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -1389,7 +1389,7 @@ if (_bufferStrategy.isOpen()) { if (log.isInfoEnabled()) - log.info("Closing journal: " + getFile()); + log.info("Closing journal in finalize: " + getFile()); shutdownNow(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WriteExecutorService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WriteExecutorService.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WriteExecutorService.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -183,7 +183,7 @@ */ final boolean trackActiveSetInMDC = false; // MUST be false for deploy - private final IResourceManager resourceManager; + private final WeakReference<IResourceManager> resourceManagerRef; /** * The name of the service if the write service is running inside of a @@ -365,7 +365,7 @@ } - this.resourceManager = resourceManager; + this.resourceManagerRef = new WeakReference<IResourceManager>(resourceManager); /* * Tracks rejected executions on a counter. @@ -947,7 +947,7 @@ * conditions? */ - final AbstractJournal journal = resourceManager.getLiveJournal(); + final AbstractJournal journal = getLiveJournal(); if(journal.isOpen()) { @@ -1790,14 +1790,29 @@ * are met. */ private boolean isShouldOverflow() { - - return resourceManager.isOverflowEnabled() + final IResourceManager rm = getResourceManager(); + + return rm.isOverflowEnabled() // && (forceOverflow.get() || resourceManager.shouldOverflow()); - && resourceManager.shouldOverflow(); + && rm.shouldOverflow(); } /** + * Not sure if there is any utility in checking for null reference. + * + * @return + */ + private IResourceManager getResourceManager() { + return resourceManagerRef.get(); + } + + private AbstractJournal getLiveJournal() { + final IResourceManager rm = getResourceManager(); + return rm == null ? null : rm.getLiveJournal(); + } + + /** * Once an overflow condition has been recognized and NO tasks are * {@link #nrunning} then {@link IResourceManager#overflow()} MAY be invoked * to handle synchronous overflow processing, including putting a new @@ -1835,7 +1850,7 @@ * Note: This returns a Future. We could use that to cancel * asynchronous overflow processing if there were a reason to do so. */ - resourceManager.overflow(); + getResourceManager().overflow(); noverflow++; @@ -2301,7 +2316,7 @@ * so there is nothing to rollback). */ - if(!resourceManager.isOpen()) { + if(getResourceManager() == null || !getResourceManager().isOpen()) { log.warn("ResourceManager not open?"); @@ -2313,7 +2328,7 @@ // note: throws IllegalStateException if resource manager is not open. // final AbstractJournal journal = resourceManager.getLiveJournal(); - final AbstractJournal journal = resourceManager.getLiveJournal(); + final AbstractJournal journal = getLiveJournal(); if(!journal.isOpen()) { @@ -2592,9 +2607,9 @@ * abort(). */ - final AbstractJournal journal = resourceManager.getLiveJournal(); + final AbstractJournal journal = getLiveJournal(); - if(journal.isOpen()) { + if (journal.isOpen()) { // Abandon the write sets. @@ -2606,15 +2621,20 @@ log.info("Did abort"); } catch(Throwable t) { + + if (getResourceManager() == null) { + log.error("Abort with collected journal: " + serviceName, t); + } else { - AbstractJournal journal = resourceManager.getLiveJournal(); + AbstractJournal journal = getLiveJournal(); + + if(journal.isOpen()) { + + log.error("Problem with abort? : "+serviceName+" : "+t, t); + + } + } - if(journal.isOpen()) { - - log.error("Problem with abort? : "+serviceName+" : "+t, t); - - } - } finally { // increment the #of aborts. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -2315,84 +2315,92 @@ * WriteCacheService, building BlobHeader as you go. **/ public long alloc(final byte buf[], final int size, - final IAllocationContext context) { + final IAllocationContext context) { - final long begin = System.nanoTime(); - - if (size > (m_maxFixedAlloc - 4)) { - - if (size > getMaxBlobSize()) - throw new IllegalArgumentException( - "Allocation request beyond maximum BLOB of " + getMaxBlobSize()); + m_allocationLock.lock(); + try { + final long begin = System.nanoTime(); - if (log.isTraceEnabled()) - log.trace("BLOB ALLOC: " + size); - - if (m_storageStats != null) { - m_storageStats.allocateBlob(size); - } + if (size > (m_maxFixedAlloc - 4)) { - final PSOutputStream psout = PSOutputStream.getNew(this, - m_maxFixedAlloc, context); - try { - - int i = 0; - 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; - } - psout.write(buf, i, size - i); + if (size > getMaxBlobSize()) + throw new IllegalArgumentException( + "Allocation request beyond maximum BLOB of " + + getMaxBlobSize()); - return psout.save(); - - } catch (IOException e) { - - throw new RuntimeException("Closed Store?", e); - - } finally { - try { - psout.close(); // return stream - } catch (IOException ioe) { - // should not happen, since this should only be - // recycling - log.warn("Unexpected error closing PSOutputStream", ioe); - } - } + if (log.isTraceEnabled()) + log.trace("BLOB ALLOC: " + size); - } + if (m_storageStats != null) { + m_storageStats.allocateBlob(size); + } - final int newAddr = alloc(size + 4, context); // allow size for checksum - - if (newAddr == 0) - throw new IllegalStateException("NULL address allocated"); + final PSOutputStream psout = PSOutputStream.getNew(this, + m_maxFixedAlloc, context); + try { - final int chk = ChecksumUtility.getCHK().checksum(buf, size); - - final long pa = physicalAddress(newAddr); + int i = 0; + 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; + } + psout.write(buf, i, size - i); - try { - m_writeCacheService.write(pa, ByteBuffer.wrap(buf, 0, size), chk, true/*writeChecksum*/, newAddr/*latchedAddr*/); - } catch (InterruptedException e) { - throw new RuntimeException("Closed Store?", e); - } + return psout.save(); - // 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(); - } + } catch (IOException e) { - return newAddr; + throw new RuntimeException("Closed Store?", e); + + } finally { + try { + psout.close(); // return stream + } catch (IOException ioe) { + // should not happen, since this should only be + // recycling + log.warn("Unexpected error closing PSOutputStream", ioe); + } + } + + } + + 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_writeCacheService.write(pa, ByteBuffer.wrap(buf, 0, size), + chk, true/* writeChecksum */, newAddr/* latchedAddr */); + } catch (InterruptedException e) { + throw new RuntimeException("Closed Store?", e); + } + + // 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; + } finally { + m_allocationLock.unlock(); + } } // /**************************************************************************** Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -150,7 +150,7 @@ final int hotCacheThreshold = 1; writeCache = new RWWriteCacheService(5/* nbuffers */, - 0/* maxDirtyListSize */, 0/*readCacheSize*/, prefixWrites, compactionThreshold, + 0/* maxDirtyListSize */, 5/*readCacheSize*/, prefixWrites, compactionThreshold, 0/*hotCacheSize*/, hotCacheThreshold, fileExtent, opener, quorum, null); Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -202,6 +202,13 @@ try { try { +// final Object tst = new Object() { +// protected void finalize() throws Throwable { +// super.finalize(); +// System.err.println("Finalizer called!!"); +// } +// }; + for (int i = 0; i < limit; i++) { final Journal jnl = new Journal(properties) { @@ -214,6 +221,7 @@ + ncreated + ", nalive=" + nunfinalized); + destroy(); } }; @@ -241,7 +249,7 @@ */ final AbstractTask task1 = new NOpTask( jnl.getConcurrencyManager(), ITx.UNISOLATED, - "name"); + "name"); /* * Task does not create an index. Since it accesses a @@ -265,16 +273,17 @@ */ final AbstractTask task2 = new RegisterIndexTask( jnl.getConcurrencyManager(), "name", - new IndexMetadata("name", UUID.randomUUID())); + new IndexMetadata("name", UUID.randomUUID()));; /* * Submit one of the tasks and *wait* for its Future. */ - jnl.getConcurrencyManager().submit(task1).get(); - jnl.getConcurrencyManager().submit(task1b).get(); - jnl.getConcurrencyManager().submit(task2).get(); + jnl.getConcurrencyManager().submit(task1).get(); + jnl.getConcurrencyManager().submit(task1b).get(); + jnl.getConcurrencyManager().submit(task2).get(); + - } catch (ExecutionException e) { + } catch (/*Execution*/Exception e) { log.error("Problem registering index: " + e, e); } @@ -369,12 +378,17 @@ /* * Ensure that all journals are destroyed by the end of the test. */ + int destroyed = 0; for (int i = 0; i < refs.length; i++) { final Journal jnl = refs[i] == null ? null : refs[i].get(); if (jnl != null) { + destroyed++; jnl.destroy(); } } + if (destroyed > 0) { + System.err.println("Destroyed " + destroyed + " non finalized journals"); + } } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -172,6 +172,8 @@ protected Journal getStore(final Properties properties) { stores = new Journal[replicationCount]; + + System.err.println("Setting stores array"); for (int i = 0; i < replicationCount; i++) { Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -58,9 +58,9 @@ import com.bigdata.concurrent.FutureTaskMon; import com.bigdata.ha.HAGlue; import com.bigdata.ha.QuorumService; -import com.bigdata.ha.halog.HALogReader; -import com.bigdata.ha.halog.HALogWriter; -import com.bigdata.ha.halog.IHALogReader; +import com.bigdata.ha.althalog.HALogFile; +import com.bigdata.ha.althalog.HALogManager; +import com.bigdata.ha.althalog.IHALogReader; import com.bigdata.ha.msg.HADigestResponse; import com.bigdata.ha.msg.HALogDigestResponse; import com.bigdata.ha.msg.HALogRootBlocksResponse; @@ -238,19 +238,9 @@ * @see Options#HA_LOG_DIR * @see HALogWriter */ - private final HALogWriter haLogWriter; + private final HALogManager haLogManager; /** - * The {@link HALogWriter} for this {@link HAJournal} and never - * <code>null</code>. - */ - HALogWriter getHALogWriter() { - - return haLogWriter; - - } - - /** * {@inheritDoc} * <p> * Overridden to strengthen the return type. @@ -297,10 +287,14 @@ } - // Set up the HA log writer. - haLogWriter = new HALogWriter(haLogDir); + // Set up the HA log manager. + haLogManager = new HALogManager(haLogDir); } + + public HALogManager getHALogManager() { + return haLogManager; + } /** * Perform some checks on the {@link HAJournal} configuration properties. @@ -416,9 +410,9 @@ */ @Override protected void _close() { - + try { - haLogWriter.disable(); + haLogManager.disable(); } catch (IOException e) { haLog.error(e, e); } @@ -445,7 +439,7 @@ if (f.isDirectory()) return true; - return f.getName().endsWith(HALogWriter.HA_LOG_EXT); + return f.getName().endsWith(HALogFile.HA_LOG_EXT); } }); @@ -589,7 +583,7 @@ final long commitCounter = msg.getCommitCounter(); final File logFile = new File(haLogDir, - HALogWriter.getHALogFileName(commitCounter)); + HALogFile.getHALogFileName(commitCounter)); if (!logFile.exists()) { @@ -598,10 +592,11 @@ } - final HALogReader r = new HALogReader(logFile); + final HALogFile haLogFile = new HALogFile(logFile); + final IHALogReader reader = haLogFile.getReader(); final HALogRootBlocksResponse resp = new HALogRootBlocksResponse( - r.getOpeningRootBlock(), r.getClosingRootBlock()); + reader.getOpeningRootBlock(), reader.getClosingRootBlock()); if (haLog.isDebugEnabled()) haLog.debug("msg=" + msg + ", resp=" + resp); @@ -625,7 +620,7 @@ * file needs to be an atomic decision and thus MUST be made by the * HALogManager. */ - final IHALogReader r = getHALogWriter().getReader(commitCounter); + final IHALogReader r = haLogManager.getReader(commitCounter); // Task sends an HALog file along the pipeline. final FutureTask<Void> ft = new FutureTaskMon<Void>( @@ -882,7 +877,7 @@ * file needs to be an atomic decision and thus MUST be made by the * HALogManager. */ - final IHALogReader r = getHALogWriter().getReader(commitCounter); + final IHALogReader r = haLogManager.getReader(commitCounter); final MessageDigest digest = MessageDigest.getInstance("MD5"); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -47,7 +47,8 @@ import com.bigdata.ha.QuorumService; import com.bigdata.ha.QuorumServiceBase; import com.bigdata.ha.RunState; -import com.bigdata.ha.halog.HALogWriter; +import com.bigdata.ha.althalog.HALogManager; +import com.bigdata.ha.althalog.IHALogWriter; import com.bigdata.ha.msg.HALogRequest; import com.bigdata.ha.msg.HALogRootBlocksRequest; import com.bigdata.ha.msg.HARebuildRequest; @@ -814,7 +815,7 @@ try { - journal.getHALogWriter().disable(); + journal.getHALogManager().disable(); } catch (IOException e) { @@ -879,7 +880,7 @@ try { - journal.getHALogWriter().createLog( + journal.getHALogManager().createLog( journal.getRootBlockView()); } catch (IOException e) { @@ -1408,9 +1409,9 @@ // Make sure we have the correct HALogWriter open. logLock.lock(); try { - final HALogWriter logWriter = journal.getHALogWriter(); - logWriter.disable(); - logWriter.createLog(openRootBlock); + final HALogManager logManager = journal.getHALogManager(); + logManager.disable(); + logManager.createLog(openRootBlock); } finally { logLock.unlock(); } @@ -1552,8 +1553,8 @@ // Close out the current HALog writer. logLock.lock(); try { - final HALogWriter logWriter = journal.getHALogWriter(); - logWriter.closeLog(closeRootBlock); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); + logWriter.close(closeRootBlock); } finally { logLock.unlock(); } @@ -1643,7 +1644,7 @@ } - final HALogWriter logWriter = journal.getHALogWriter(); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); if (haLog.isDebugEnabled()) haLog.debug("HALog.commitCounter=" @@ -1746,7 +1747,7 @@ if (HA_LOG_ENABLED) { - final HALogWriter logWriter = journal.getHALogWriter(); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); if (msg.getCommitCounter() == logWriter.getCommitCounter() && msg.getSequence() == (logWriter.getSequence() - 1)) { @@ -1878,7 +1879,7 @@ * files. */ - final HALogWriter logWriter = journal.getHALogWriter(); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); final long journalCommitCounter = journal.getRootBlockView() .getCommitCounter(); @@ -1961,7 +1962,7 @@ private void resyncTransitionToMetQuorum(final IHAWriteMessage msg, final ByteBuffer data) throws IOException, InterruptedException { - final HALogWriter logWriter = journal.getHALogWriter(); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); final IRootBlockView rootBlock = journal.getRootBlockView(); @@ -2030,7 +2031,7 @@ if (HA_LOG_ENABLED) { - final HALogWriter logWriter = journal.getHALogWriter(); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); if (msg.getCommitCounter() != logWriter.getCommitCounter()) { @@ -2067,7 +2068,9 @@ try { - journal.getHALogWriter().write(msg, data); + final IHALogWriter logWriter = journal.getHALogManager().getOpenLogFile().getWriter(); + + logWriter.write(msg, data); } finally { @@ -2132,12 +2135,14 @@ logLock.lock(); try { - + final HALogManager logManager = journal.getHALogManager(); + final IHALogWriter logWriter = logManager.getOpenLogFile().getWriter(); + // Close off the old log file with the root block. - journal.getHALogWriter().closeLog(rootBlock); + logWriter.close(rootBlock); // Open up a new log file with this root block. - journal.getHALogWriter().createLog(rootBlock); + logManager.createLog(rootBlock); } finally { @@ -2161,49 +2166,7 @@ logLock.lock(); try { - - final File logDir = journal.getHALogDir(); - - final File[] files = logDir.listFiles(new FilenameFilter() { - - @Override - public boolean accept(final File dir, final String name) { - - return name.endsWith(HALogWriter.HA_LOG_EXT); - - } - }); - - int ndeleted = 0; - long totalBytes = 0L; - - final File currentFile = journal.getHALogWriter().getFile(); - - for (File file : files) { - - final long len = file.length(); - - final boolean delete = includeCurrent - || currentFile != null - && file.getName().equals(currentFile.getName()); - - if (delete && !file.delete()) { - - haLog.warn("COULD NOT DELETE FILE: " + file); - - continue; - - } - - ndeleted++; - - totalBytes += len; - - } - - haLog.info("PURGED LOGS: ndeleted=" + ndeleted - + ", totalBytes=" + totalBytes); - + journal.getHALogManager().removeAllLogFiles(includeCurrent); } finally { logLock.unlock(); Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-01-22 20:46:21 UTC (rev 6817) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-01-23 14:21:12 UTC (rev 6818) @@ -163,6 +163,8 @@ // Start 3rd service. final HAGlue serverC = startC(); + awaitKBExists(serverC); + // Wait until the quorum is fully met. The token should not change. assertEquals(token, awaitFullyMetQuorum()); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-01-23 18:59:38
|
Revision: 6820 http://bigdata.svn.sourceforge.net/bigdata/?rev=6820&view=rev Author: thompsonbry Date: 2013-01-23 18:59:30 +0000 (Wed, 23 Jan 2013) Log Message: ----------- My edits from code review of READ_CACHE with Martyn. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IBackingReader.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IWriteCache.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/Options.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/VerifyCommitRecordIndex.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestTx.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -34,11 +34,9 @@ import java.security.DigestException; import java.security.MessageDigest; import java.util.Formatter; -import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.log4j.Logger; @@ -163,7 +161,7 @@ // protected by m_writeLock private long m_writePosition = -1; - private AtomicLong m_sequence = new AtomicLong(0); + private long m_sequence = 0; /** * This constructor is called by the log manager to create the file. A @@ -341,7 +339,7 @@ + m_openRootBlock.getLastCommitTime() + ", but msg=" + msg); - if (m_sequence.get() != msg.getSequence()) + if (m_sequence != msg.getSequence()) throw new IllegalStateException("nextSequence=" + m_sequence + ", but msg=" + msg); @@ -392,7 +390,7 @@ throw new AssertionError(); } - m_sequence.incrementAndGet(); + m_sequence++; m_fileChange.signalAll(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IBackingReader.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IBackingReader.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IBackingReader.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -41,9 +41,9 @@ * {@link ByteBuffer#remaining()} bytes will be read into the caller's * buffer, starting at the specified offset in the backing file. * - * @param offset - * The offset of the first byte (relative to the start of the - * data region). + * @param fileOffset + * The offset of the first byte to be read (absolute offset on + * the backing file). * @param dst * Where to put the data. Bytes will be written at position until * limit. @@ -51,6 +51,6 @@ * @return The caller's buffer, prepared for reading back the installed * record. */ - public ByteBuffer readRaw(long offset, ByteBuffer dst); + public ByteBuffer readRaw(long fileOffset, ByteBuffer dst); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IWriteCache.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IWriteCache.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/IWriteCache.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -44,42 +44,6 @@ */ public interface IWriteCache { -// /** -// * Write the record on the cache. This interface DOES NOT provide any -// * guarantee about the ordering of writes. Callers who require a specific -// * ordering must coordinate that ordering themselves, e.g., by synchronizing -// * across their writes onto the cache. -// * -// * @param offset -// * The offset of that record (maybe relative to a base offset). -// * @param data -// * The record. 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 cache (i.e., the data are copied into the cache). -// * -// * @return <code>true</code> iff the caller's record was transferred to the -// * cache. When <code>false</code>, there is not enough room left in -// * the write cache for this record. -// * -// * @throws InterruptedException -// * @throws IllegalStateException -// * If the buffer is closed. -// * @throws IllegalArgumentException -// * If the caller's record is larger than the maximum capacity of -// * cache (the record could not fit within the cache). The caller -// * should check for this and provide special handling for such -// * large records. For example, they can be written directly onto -// * the backing channel. -// * -// * @deprecated by {@link #writeChk(long, ByteBuffer, int)} -// */ -// public boolean write(final long offset, final ByteBuffer data) -// throws InterruptedException; - /** * Write the record on the cache. This interface DOES NOT provide any * guarantee about the ordering of writes. Callers who require a specific @@ -87,7 +51,7 @@ * across their writes onto the cache. * * @param offset - * The offset of that record (maybe relative to a base offset). + * The file offset of that record in the backing file. * @param data * The record. The bytes from the current * {@link ByteBuffer#position()} to the @@ -122,8 +86,8 @@ /** * Read a record from the write cache. * - * @param offset - * The offset of that record (maybe relative to a base offset). + * @param offset + * The file offset of that record in the backing file. * @param nbytes * The length of the record (decoded from the address by the * caller). @@ -146,36 +110,6 @@ public ByteBuffer read(final long offset, final int nbytes) throws InterruptedException, ChecksumError; -// /** -// * Update a record in the write cache. -// * -// * @param addr -// * The address of the record. -// * @param off -// * The byte offset of the update. -// * @param data -// * The data to be written onto the record in the cache starting -// * at that byte offset. 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 -// * cache (i.e., the data are copied into the cache). -// * -// * @return <code>true</code> iff the record was updated and -// * <code>false</code> if no record for that address was found in the -// * cache. -// * -// * @throws InterruptedException -// * @throws IllegalStateException -// * -// * @throws IllegalStateException -// * if the buffer is closed. -// */ -// public boolean update(final long addr, final int off, final ByteBuffer data) -// throws IllegalStateException, InterruptedException; - /** * Flush the writes to the backing channel but does not force anything to * the backing channel. The caller is responsible for managing when the Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -1389,7 +1389,7 @@ if (_bufferStrategy.isOpen()) { if (log.isInfoEnabled()) - log.info("Closing journal in finalize: " + getFile()); + log.info("Closing journal: " + getFile()); shutdownNow(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -170,10 +170,10 @@ /** * Used to support the rebuild protocol. * - * @param position - absolute file offset + * @param fileOffset - absolute file offset * @param transfer - target buffer for read */ - ByteBuffer readRaw(long position, ByteBuffer transfer); + ByteBuffer readRaw(long fileOffset, ByteBuffer transfer); /** * Used to support the rebuild protocol Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/Options.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/Options.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/Options.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -240,24 +240,43 @@ String WRITE_CACHE_BUFFER_COUNT = AbstractJournal.class.getName()+".writeCacheBufferCount"; /** + * <strong>ALPHA FEATURE</strong> + * <p> * Option may be used to override the #of {@link ReadCache} buffers which - * will be used with a {@link WriteCacheService}. + * will be used with a {@link WriteCacheService}. When ZERO (0) the read + * cache is disabled. + * <p> + * The purpose of the read cache is to provide additional buffering of the + * disk under the control of the database. When enabled, records read from + * the disk are installed into the read cache as well as write cache records + * once they have been flushed to the disk. Records evicted from the read + * cache are transferred to the hot cache (if enabled) if they have been + * touched multiple times while on the read cache. * * @see #DEFAULT_READ_CACHE_BUFFER_COUNT + * @see #HOT_CACHE_SIZE */ String READ_CACHE_BUFFER_COUNT = AbstractJournal.class.getName()+".readCacheBufferCount"; /** - * Option may be used to override the threshold at which retained readCache records - * are moved to the hotCache which will be used with a {@link WriteCacheService}. + * <strong>ALPHA FEATURE</strong> + * <p> + * Option may be used to override the #of touches at which a retained + * readCache record is moved to the hotCache. Records which are touched + * multiple times while on the read cache are transferred to the hot cache. + * Records evicted from the hot cache are dropped back to the read cache + * where they get a chance to demonstrate that they are still hot before + * being evicted from the read cache. * * @see #DEFAULT_HOT_CACHE_THRESHOLD */ String HOT_CACHE_THRESHOLD = AbstractJournal.class.getName()+".hotCacheThreshold"; /** - * Option may be used to override the number of hotCache buffers which will be - * used with a {@link WriteCacheService}. + * <strong>ALPHA FEATURE</strong> + * <p> + * Option may be used to override the number of hotCache buffers which will + * be used with a {@link WriteCacheService}. * * @see #DEFAULT_HOT_CACHE_SIZE */ @@ -632,10 +651,10 @@ */ String DEFAULT_WRITE_CACHE_COMPACTION_THRESHOLD = "20"; - /** - * The default for {@link #READ_CACHE_MAX_RECORD_SIZE}. - */ - String DEFAULT_READ_CACHE_MAX_RECORD_SIZE = ""+(2*Bytes.kilobyte); +// /** +// * The default for {@link #READ_CACHE_MAX_RECORD_SIZE}. +// */ +// String DEFAULT_READ_CACHE_MAX_RECORD_SIZE = ""+(2*Bytes.kilobyte); /** * The default for {@link #HOT_CACHE_THRESHOLD}. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/VerifyCommitRecordIndex.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/VerifyCommitRecordIndex.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/VerifyCommitRecordIndex.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -94,6 +94,8 @@ final int removed = jrnl.removeCommitRecordEntries(zeroKey, releaseKey); + System.out.println("Commit Record Index verified with " + removed + " records removed"); + jrnl.commit(); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -980,7 +980,7 @@ final long fileExtent, final IReopenChannel<? extends Channel> opener, final Quorum quorum) throws InterruptedException { - + // Note: Compaction explicitly disabled for the WORM. super(writeCacheBufferCount, 0/* maxDirtyListSize */, readCacheBufferCount, false/* prefixWrites */, 100/* compactionThreshold */, hotCacheSize, hotCacheThreshold, useChecksums, extent, opener, quorum, WORMStrategy.this /*reader*/); Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -30,7 +30,6 @@ import java.lang.ref.WeakReference; import java.util.Properties; import java.util.UUID; -import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import junit.framework.TestCase2; @@ -202,13 +201,6 @@ try { try { -// final Object tst = new Object() { -// protected void finalize() throws Throwable { -// super.finalize(); -// System.err.println("Finalizer called!!"); -// } -// }; - for (int i = 0; i < limit; i++) { final Journal jnl = new Journal(properties) { @@ -221,6 +213,7 @@ + ncreated + ", nalive=" + nunfinalized); + // ensure that journals are destroyed when the are finalized. destroy(); } }; @@ -273,7 +266,7 @@ */ final AbstractTask task2 = new RegisterIndexTask( jnl.getConcurrencyManager(), "name", - new IndexMetadata("name", UUID.randomUUID()));; + new IndexMetadata("name", UUID.randomUUID())); /* * Submit one of the tasks and *wait* for its Future. @@ -282,7 +275,6 @@ jnl.getConcurrencyManager().submit(task1b).get(); jnl.getConcurrencyManager().submit(task2).get(); - } catch (/*Execution*/Exception e) { log.error("Problem registering index: " + e, e); } @@ -387,7 +379,7 @@ } } if (destroyed > 0) { - System.err.println("Destroyed " + destroyed + " non finalized journals"); + log.error("Destroyed " + destroyed + " non finalized journals"); } } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestTx.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestTx.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestTx.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -1256,7 +1256,7 @@ */ public void testStress() throws InterruptedException, ExecutionException { - final int ntx = 100; // 30; + final int ntx = 30; final int nops = 10000; final Journal store = getStore(); Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-01-23 18:17:20 UTC (rev 6819) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-01-23 18:59:30 UTC (rev 6820) @@ -163,8 +163,6 @@ // Start 3rd service. final HAGlue serverC = startC(); - awaitKBExists(serverC); - // Wait until the quorum is fully met. The token should not change. assertEquals(token, awaitFullyMetQuorum()); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-01-25 15:57:38
|
Revision: 6850 http://bigdata.svn.sourceforge.net/bigdata/?rev=6850&view=rev Author: thompsonbry Date: 2013-01-25 15:57:25 +0000 (Fri, 25 Jan 2013) Log Message: ----------- Removed well-intentioned API for coordinating HA rebuild with the underlying IHABufferStrategy. I feel that the HAJournalServer should own the awareness of the HA state transitions. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java 2013-01-25 15:13:13 UTC (rev 6849) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IHABufferStrategy.java 2013-01-25 15:57:25 UTC (rev 6850) @@ -186,16 +186,16 @@ void writeRawBuffer(HARebuildRequest req, IHAWriteMessage msg, ByteBuffer transfer) throws IOException; - /** - * Sets strategy to be ready to rebuild store - * @param req - */ - void prepareForRebuild(HARebuildRequest req); +// /** +// * Sets strategy to be ready to rebuild store +// * @param req +// */ +// void prepareForRebuild(HARebuildRequest req); +// +// /** +// * Informs strategy to reload from rebuilt store +// * @param req +// */ +// void completeRebuild(HARebuildRequest req, IRootBlockView rbv); - /** - * Informs strategy to reload from rebuilt store - * @param req - */ - void completeRebuild(HARebuildRequest req, IRootBlockView rbv); - } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2013-01-25 15:13:13 UTC (rev 6849) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2013-01-25 15:57:25 UTC (rev 6850) @@ -839,11 +839,11 @@ if (req == null) throw new IllegalArgumentException(); - if (m_rebuildSequence != msg.getSequence()) - throw new IllegalStateException( - "Invalid sequence number for rebuild, expected: " - + m_rebuildSequence + ", actual: " - + msg.getSequence()); +// if (m_rebuildSequence != msg.getSequence()) +// throw new IllegalStateException( +// "Invalid sequence number for rebuild, expected: " +// + m_rebuildSequence + ", actual: " +// + msg.getSequence()); m_store.writeRaw(msg.getFirstOffset(), transfer); @@ -851,21 +851,21 @@ log.debug("Transfer rebuild: " + msg.getSequence() + ", address: " + msg.getFirstOffset()); - m_rebuildSequence++; +// m_rebuildSequence++; } - private int m_rebuildSequence = -1; - - @Override - public void prepareForRebuild(final HARebuildRequest req) { - m_store.prepareForRebuild(req); - m_rebuildSequence = 0; - } +// private int m_rebuildSequence = -1; +// +// @Override +// public void prepareForRebuild(final HARebuildRequest req) { +// m_store.prepareForRebuild(req); +// m_rebuildSequence = 0; +// } +// +// @Override +// public void completeRebuild(final HARebuildRequest req, final IRootBlockView rbv) { +// m_store.completeRebuild(req, rbv); +// m_rebuildSequence = -1; +// } - @Override - public void completeRebuild(final HARebuildRequest req, final IRootBlockView rbv) { - m_store.completeRebuild(req, rbv); - m_rebuildSequence = -1; - } - } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-01-25 15:13:13 UTC (rev 6849) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-01-25 15:57:25 UTC (rev 6850) @@ -1903,9 +1903,9 @@ */ private final ByteBuffer _checkbuf; - private HARebuildRequest m_rebuildRequest; - - private int m_rebuildSequence; +// private HARebuildRequest m_rebuildRequest; +// +// private int m_rebuildSequence; /** * Make sure that the file is large enough to accept a write of @@ -2672,35 +2672,35 @@ @Override public void writeRawBuffer(HARebuildRequest req, IHAWriteMessage msg, ByteBuffer transfer) throws IOException { - if (m_rebuildRequest == null) - throw new IllegalStateException("Store is not in rebuild state"); - - if (m_rebuildSequence != msg.getSequence()) - throw new IllegalStateException("Invalid sequence number for rebuild, expected: " + m_rebuildSequence + ", actual: " + msg.getSequence()); +// if (m_rebuildRequest == null) +// throw new IllegalStateException("Store is not in rebuild state"); +// +// if (m_rebuildSequence != msg.getSequence()) +// throw new IllegalStateException("Invalid sequence number for rebuild, expected: " + m_rebuildSequence + ", actual: " + msg.getSequence()); FileChannelUtility.writeAll(this.opener, transfer, msg.getFirstOffset()); - m_rebuildSequence++; +// m_rebuildSequence++; } - @Override - public void prepareForRebuild(HARebuildRequest req) { - assert m_rebuildRequest == null; - - m_rebuildRequest = req; - m_rebuildSequence = 0; - } - - @Override - public void completeRebuild(final HARebuildRequest req, final IRootBlockView rbv) { - assert m_rebuildRequest != null; - - assert m_rebuildRequest.equals(req); - - // TODO: reinit from file - this.resetFromHARootBlock(rbv); - - m_rebuildRequest = null; - } +// @Override +// public void prepareForRebuild(HARebuildRequest req) { +// assert m_rebuildRequest == null; +// +// m_rebuildRequest = req; +// m_rebuildSequence = 0; +// } +// +// @Override +// public void completeRebuild(final HARebuildRequest req, final IRootBlockView rbv) { +// assert m_rebuildRequest != null; +// +// assert m_rebuildRequest.equals(req); +// +// // TODO: reinit from file +// this.resetFromHARootBlock(rbv); +// +// m_rebuildRequest = null; +// } } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-01-25 15:13:13 UTC (rev 6849) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-01-25 15:57:25 UTC (rev 6850) @@ -959,9 +959,6 @@ } } - // make this field public for access from unit tests as required - public static boolean DEBUG_USEREADCACHE = true; - /** * Create and return a new {@link RWWriteCacheService} instance. The caller * is responsible for closing out the old one and must be holding the @@ -978,7 +975,7 @@ return new RWWriteCacheService(m_writeCacheBufferCount, m_maxDirtyListSize, m_readCacheBufferCount, prefixWrites, m_compactionThreshold, m_hotCacheSize, m_hotCacheThreshold, - convertAddr(m_fileSize), m_reopener, m_quorum, DEBUG_USEREADCACHE ? this : null) { + convertAddr(m_fileSize), m_reopener, m_quorum, this) { @SuppressWarnings("unchecked") public WriteCache newWriteCache(final IBufferAccess buf, @@ -1625,7 +1622,7 @@ try { assertOpen(); // check again after taking lock - assertNoRebuild(); +// assertNoRebuild(); // length includes space for the checksum if (length > m_maxFixedAlloc) { @@ -1833,13 +1830,13 @@ } } - /** - * Convenience check for thoseA batch invoice public methods that must be restricted if a rebuild is in progress - */ - private void assertNoRebuild() { - if (m_rebuildRequest != null) - throw new IllegalStateException("Invalid when rebuilding"); - } +// /** +// * Convenience check for thoseA batch invoice public methods that must be restricted if a rebuild is in progress +// */ +// private void assertNoRebuild() { +// if (m_rebuildRequest != null) +// throw new IllegalStateException("Invalid when rebuilding"); +// } private void assertAllocators() { for (int i = 0; i < m_allocs.size(); i++) { @@ -1893,7 +1890,7 @@ */ public void free(final long laddr, final int sze, final IAllocationContext context) { assertOpen(); - assertNoRebuild(); +// assertNoRebuild(); final int addr = (int) laddr; switch (addr) { @@ -2532,7 +2529,7 @@ m_allocationLock.lock(); try { assertOpen(); - assertNoRebuild(); +// assertNoRebuild(); boolean isolatedWrites = false; /** @@ -2694,7 +2691,7 @@ public void commit() { assertOpen(); - assertNoRebuild(); +// assertNoRebuild(); checkCoreAllocations(); @@ -4678,7 +4675,7 @@ public ByteBuffer readRootBlock(final boolean rootBlock0) { assertOpen(); - assertNoRebuild(); +// assertNoRebuild(); final ByteBuffer tmp = ByteBuffer .allocate(RootBlockView.SIZEOF_ROOT_BLOCK); @@ -5851,7 +5848,7 @@ private long lastBlockSequence = 0; - private HARebuildRequest m_rebuildRequest = null; +// private HARebuildRequest m_rebuildRequest = null; // /** // * Only blacklist the addr if not already available, in other words @@ -5980,27 +5977,27 @@ * @throws IOException */ public void writeRaw(final long offset, final ByteBuffer transfer) throws IOException { - if (m_rebuildRequest == null) - throw new IllegalStateException("Store is not in rebuild state"); +// if (m_rebuildRequest == null) +// throw new IllegalStateException("Store is not in rebuild state"); FileChannelUtility.writeAll(m_reopener, transfer, offset); } - public void prepareForRebuild(final HARebuildRequest req) { - assert m_rebuildRequest == null; - - m_rebuildRequest = req; - } +// public void prepareForRebuild(final HARebuildRequest req) { +// assert m_rebuildRequest == null; +// +// m_rebuildRequest = req; +// } +// +// public void completeRebuild(final HARebuildRequest req, final IRootBlockView rbv) { +// assert m_rebuildRequest != null; +// +// assert m_rebuildRequest.equals(req); +// +// // TODO: reinit from file +// this.resetFromHARootBlock(rbv); +// +// m_rebuildRequest = null; +// } - public void completeRebuild(final HARebuildRequest req, final IRootBlockView rbv) { - assert m_rebuildRequest != null; - - assert m_rebuildRequest.equals(req); - - // TODO: reinit from file - this.resetFromHARootBlock(rbv); - - m_rebuildRequest = null; - } - } Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java 2013-01-25 15:13:13 UTC (rev 6849) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java 2013-01-25 15:57:25 UTC (rev 6850) @@ -6,25 +6,21 @@ import java.util.Random; import java.util.UUID; +import junit.framework.TestCase; + import com.bigdata.ha.msg.HARebuildRequest; import com.bigdata.ha.msg.HAWriteMessage; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.journal.BufferMode; import com.bigdata.journal.FileMetadata; import com.bigdata.journal.ForceEnum; -import com.bigdata.journal.IBufferStrategy; +import com.bigdata.journal.IHABufferStrategy; import com.bigdata.journal.IRootBlockView; -import com.bigdata.journal.RWStrategy; -import com.bigdata.journal.IHABufferStrategy; import com.bigdata.journal.Journal; import com.bigdata.journal.Options; import com.bigdata.journal.RootBlockView; -import com.bigdata.journal.StoreTypeEnum; -import com.bigdata.rwstore.RWStore; import com.bigdata.util.ChecksumUtility; -import junit.framework.TestCase; - /** * Shortcuts the HA transfer protocols to exercise directly the low level * data transfers at the BufferStrategy interface. @@ -34,8 +30,18 @@ */ public class TestRawTransfers extends TestCase { - final Random random = new Random(); + private Random random; + protected void setUp() throws Exception { + super.setUp(); + random = new Random(); + } + + protected void tearDown() throws Exception { + random = null; + super.tearDown(); + } + /** * Create two stores: * add data to one @@ -72,9 +78,9 @@ final ByteBuffer transfer = ByteBuffer.allocate(1024 * 1024); long position = FileMetadata.headerSize0; - // AN HARebuild request must be sent to the destination resulting in - // a prepareForRebuild request. - dst.prepareForRebuild(req); +// // AN HARebuild request must be sent to the destination resulting in +// // a prepareForRebuild request. +// dst.prepareForRebuild(req); // transfer full file store long sequence = 0; @@ -111,7 +117,8 @@ final IRootBlockView activeRbv = rbv0.getCommitCounter() > rbv1.getCommitCounter() ? rbv0 : rbv1; - dst.completeRebuild(req, activeRbv); +// dst.completeRebuild(req, activeRbv); + dst.resetFromHARootBlock(activeRbv); // now see if we can read the data written to the first journal from the second data.position(0); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-01-25 19:04:44
|
Revision: 6858 http://bigdata.svn.sourceforge.net/bigdata/?rev=6858&view=rev Author: thompsonbry Date: 2013-01-25 19:04:24 +0000 (Fri, 25 Jan 2013) Log Message: ----------- Merging changes from the dev branch into the READ_CACHE branch. {{{ >From r6766 to HEAD (r6857) of /branches/BIGDATA_RELEASE_1_2_0 To /branches/READ_CACHE }}} SVN COMMAND: {{{ merge https://bigdata.svn.sourceforge.net/svnroot/bigdata/branches/BIGDATA_RELEASE_1_2_0 /Users/bryan/Documents/workspace/BIGDATA_READ_CACHE_HEAD }}} {{{ Merge complete. ===== File Statistics: ===== Deleted: 8 Added: 25 Updated: 139 ==== Property Statistics: ===== Updated: 50 ==== Conflict Statistics: ===== File conflicts: 3 C /Users/bryan/Documents/workspace/BIGDATA_READ_CACHE_HEAD/bigdata/src/test/com/bigdata/rwstore/sector/TestMemStore.java C /Users/bryan/Documents/workspace/BIGDATA_READ_CACHE_HEAD/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java C /Users/bryan/Documents/workspace/BIGDATA_READ_CACHE_HEAD/bigdata/src/java/com/bigdata/journal/WriteExecutorService.java }}} Accepted the incoming version for all three conflicts. These files had been modified in the same manner in the dev branch and the READ_CACHE branch. @see https://sourceforge.net/apps/trac/bigdata/ticket/621 (Coalesce write cache records and install reads in cache) Revision Links: -------------- http://bigdata.svn.sourceforge.net/bigdata/?rev=6766&view=rev http://bigdata.svn.sourceforge.net/bigdata/?rev=6857&view=rev Modified Paths: -------------- branches/READ_CACHE/.classpath branches/READ_CACHE/bigdata/src/java/com/bigdata/bfs/BigdataFileSystem.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/BOpUtility.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/Var.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/controller/ServiceCallJoin.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/fed/QueryEngineFactory.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/join/PipelineJoin.java branches/READ_CACHE/bigdata/src/java/com/bigdata/btree/raba/codec/CanonicalHuffmanRabaCoder.java branches/READ_CACHE/bigdata/src/java/com/bigdata/btree/raba/codec/FrontCodedRabaCoder.java branches/READ_CACHE/bigdata/src/java/com/bigdata/btree/raba/codec/ICodedRaba.java branches/READ_CACHE/bigdata/src/java/com/bigdata/btree/raba/codec/IRabaCoder.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/CommitRecordIndex.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WriteExecutorService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/relation/AbstractResource.java branches/READ_CACHE/bigdata/src/java/com/bigdata/search/FullTextIndex.java branches/READ_CACHE/bigdata/src/test/com/bigdata/bop/join/TestNestedLoopJoinOp.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestJournalShutdown.java branches/READ_CACHE/bigdata/src/test/com/bigdata/rwstore/sector/TestMemStore.java branches/READ_CACHE/bigdata-gom/src/test/com/bigdata/gom/TestNumericBNodes.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/jini/start/process/ProcessHelper.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/bop/rdf/update/ParseOp.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/ServiceProviderHook.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/BSBMExtensionFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/DefaultExtensionFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/IExtensionFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/ILexiconConfiguration.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/IVUtility.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/LexiconConfiguration.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/NoExtensionFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/impl/AbstractIV.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/impl/literal/NumericIV.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/lexicon/LexiconRelation.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/load/MappedRDFDataLoadMaster.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/properties/PropertiesFormat.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/nquads/NQuadsParser.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/nquads/NQuadsParserFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/ntriples/BigdataNTriplesParser.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/ntriples/BigdataNTriplesParserFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/Att.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/Atts.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/BigdataRDFXMLParser.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/BigdataRDFXMLParserFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/BigdataRDFXMLWriter.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/BigdataRDFXMLWriterFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/rdfxml/SAXFilter.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/turtle/BigdataTurtleParser.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/rio/turtle/BigdataTurtleParserFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/FunctionRegistry.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/HavingNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/QueryHints.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/StaticAnalysis.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/StaticAnalysisBase.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/VarNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/cache/CacheConnectionFactory.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/eval/AST2BOpUpdate.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/eval/AST2BOpUtility.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/eval/ASTSearchOptimizer.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/optimizers/ASTJoinOrderByTypeOptimizer.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/optimizers/ASTWildcardProjectionOptimizer.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/optimizers/DefaultOptimizerList.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/service/RemoteSparql10QueryBuilder.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/service/RemoteSparql11QueryBuilder.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/service/ServiceCallUtility.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/spo/SPORelation.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/store/AbstractTripleStore.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/store/BD.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/store/LocalTripleStore.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/internal/HashCollisionUtility.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/internal/SampleExtensionFactory.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/lexicon/TestFullTextIndex.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/lexicon/TestSubjectCentricFullTextIndex.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/rio/nquads/TestNQuadsParser.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/rio/nquads/TestNQuadsParserFactory.java branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/rio/rdfxml/RDFXMLWriterTestCase.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/remote/BigdataSailRemoteRepository.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ASTVisitorBase.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BaseDeclProcessor.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BatchRDFValueResolver.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/Bigdata2ASTSPARQLParser.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BigdataASTContext.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BigdataASTVisitorBase.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BigdataExprBuilder.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BigdataParsedQuery.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BigdataParsedUpdate.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/BlankNodeVarProcessor.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/DatasetDeclProcessor.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/GroupGraphPattern.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/GroupGraphPatternBuilder.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/NegatedPropertySet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/PrefixDeclProcessor.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/PropertySetElem.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/SPARQLUtil.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/StringEscapesProcessor.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/TriplePatternExprBuilder.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/UpdateExprBuilder.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ValueExprBuilder.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/ASTOperationContainer.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/ASTQueryContainer.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/ASTSelect.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/ASTSelectQuery.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/ASTUpdateContainer.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/ASTUpdateSequence.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/SyntaxTreeBuilder.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/SyntaxTreeBuilderConstants.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/SyntaxTreeBuilderTokenManager.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/sparql.jj branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/sparql/ast/sparql.jjt branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/BigdataRDFServlet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/BigdataRDFServletContextListener.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/BigdataServlet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/ConnegUtil.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/DeleteServlet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/InsertServlet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/QueryServlet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/UpdateServlet.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/ConnectOptions.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/IRemoteRepository.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/RemoteRepository.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/RemoteRepositoryManager.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/TestAll.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/TestBigdataSailWithQuads.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/sparql/AbstractBigdataExprBuilderTestCase.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/sparql/Bigdata2ASTSPARQL11SyntaxTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/sparql/TestAll.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/sparql/TestAll_AST.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/sparql/TestBigdataExprBuilder.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataComplexSparqlQueryTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataConnectionTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataSparqlTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/TestAll.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/TestBigdataSailRemoteRepository.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/ComplexSPARQLQueryTest.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/EarlReport.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/SPARQLASTQueryTest.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/SPARQLQueryTest.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/SPARQLUpdateTest.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/sail/RDFStoreTest.java branches/READ_CACHE/bigdata-war/src/resources/WEB-INF/web.xml branches/READ_CACHE/build.properties branches/READ_CACHE/build.xml Added Paths: ----------- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ArbitraryLengthPathOp.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ZeroLengthPathOp.java branches/READ_CACHE/bigdata-rdf/lib/openrdf-sesame-2.6.10-onejar.jar branches/READ_CACHE/bigdata-rdf/lib/sesame-rio-testsuite-2.6.10.jar branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/ArbitraryLengthPathNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/PathNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/PropertyPathNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/PropertyPathUnionNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/ZeroLengthPathNode.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/optimizers/ASTPropertyPathOptimizer.java branches/READ_CACHE/bigdata-sails/lib/sesame-sparql-testsuite-2.6.10.jar branches/READ_CACHE/bigdata-sails/lib/sesame-store-testsuite-2.6.10.jar branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/AST2SPARQLUtil.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/EncodeDecodeValue.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/IMimeTypes.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/client/MiniMime.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/TestTicket632.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/sparql/BigdataSPARQL2ASTParserTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataArbitraryLengthPathTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/tck/BigdataSPARQLUpdateConformanceTest.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/client/ branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/client/TestAll.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/client/TestEncodeDecodeValue.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/SPARQL11SyntaxTest.java Removed Paths: ------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ArbitraryLengthPathOp.java branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ZeroLengthPathOp.java branches/READ_CACHE/bigdata-rdf/lib/openrdf-sesame-2.6.3-onejar.jar branches/READ_CACHE/bigdata-rdf/lib/sesame-rio-testsuite-2.6.3.jar branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/AST2SPARQLUtil.java branches/READ_CACHE/bigdata-sails/lib/sesame-sparql-testsuite-2.6.3.jar branches/READ_CACHE/bigdata-sails/lib/sesame-store-testsuite-2.6.3.jar branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/EncodeDecodeValue.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/MiniMime.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/TestEncodeDecodeValue.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/client/TestAll.java branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/client/TestEncodeDecodeValue.java Property Changed: ---------------- branches/READ_CACHE/ branches/READ_CACHE/bigdata/lib/jetty/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/aggregate/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/joinGraph/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/util/ branches/READ_CACHE/bigdata/src/java/com/bigdata/htree/raba/ branches/READ_CACHE/bigdata/src/java/com/bigdata/jsr166/ branches/READ_CACHE/bigdata/src/test/com/bigdata/bop/joinGraph/ branches/READ_CACHE/bigdata/src/test/com/bigdata/bop/util/ branches/READ_CACHE/bigdata/src/test/com/bigdata/jsr166/ branches/READ_CACHE/bigdata/src/test/com/bigdata/util/httpd/ branches/READ_CACHE/bigdata-compatibility/ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/attr/ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/disco/ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/util/config/ branches/READ_CACHE/bigdata-perf/ branches/READ_CACHE/bigdata-perf/btc/ branches/READ_CACHE/bigdata-perf/btc/src/resources/ branches/READ_CACHE/bigdata-perf/lubm/ branches/READ_CACHE/bigdata-perf/uniprot/ branches/READ_CACHE/bigdata-perf/uniprot/src/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/bop/rdf/aggregate/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/changesets/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/error/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/relation/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/util/ branches/READ_CACHE/bigdata-rdf/src/samples/ branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/bop/rdf/aggregate/ branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/internal/ branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/relation/ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/bench/ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/changesets/ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/ branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/bench/ branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/ branches/READ_CACHE/dsi-utils/ branches/READ_CACHE/dsi-utils/LEGAL/ branches/READ_CACHE/dsi-utils/lib/ branches/READ_CACHE/dsi-utils/src/ branches/READ_CACHE/dsi-utils/src/java/ branches/READ_CACHE/dsi-utils/src/java/it/ branches/READ_CACHE/dsi-utils/src/java/it/unimi/ branches/READ_CACHE/dsi-utils/src/test/ branches/READ_CACHE/dsi-utils/src/test/it/unimi/ branches/READ_CACHE/dsi-utils/src/test/it/unimi/dsi/ branches/READ_CACHE/lgpl-utils/src/java/it/unimi/dsi/fastutil/bytes/custom/ branches/READ_CACHE/lgpl-utils/src/test/it/unimi/dsi/fastutil/bytes/custom/ branches/READ_CACHE/osgi/ branches/READ_CACHE/src/resources/bin/config/ Property changes on: branches/READ_CACHE ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BTREE_BUFFER_BRANCH:2004-2045 /branches/DEV_BRANCH_27_OCT_2009:2270-2546,2548-2782 /branches/INT64_BRANCH:4486-4522 /branches/JOURNAL_HA_BRANCH:2596-4066 /branches/LARGE_LITERALS_REFACTOR:4175-4387 /branches/LEXICON_REFACTOR_BRANCH:2633-3304 /branches/QUADS_QUERY_BRANCH:4525-4531,4550-4584,4586-4609,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH:4814-4836 /branches/bugfix-btm:2594-3237 /branches/dev-btm:2574-2730 /branches/fko:3150-3194 /trunk:3392-3437,3656-4061 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE:6769-6785 /branches/BIGDATA_RELEASE_1_2_0:6766-6857 /branches/BTREE_BUFFER_BRANCH:2004-2045 /branches/DEV_BRANCH_27_OCT_2009:2270-2546,2548-2782 /branches/INT64_BRANCH:4486-4522 /branches/JOURNAL_HA_BRANCH:2596-4066 /branches/LARGE_LITERALS_REFACTOR:4175-4387 /branches/LEXICON_REFACTOR_BRANCH:2633-3304 /branches/QUADS_QUERY_BRANCH:4525-4531,4550-4584,4586-4609,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH:4814-4836 /branches/bugfix-btm:2594-3237 /branches/dev-btm:2574-2730 /branches/fko:3150-3194 /trunk:3392-3437,3656-4061 Modified: branches/READ_CACHE/.classpath =================================================================== --- branches/READ_CACHE/.classpath 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/.classpath 2013-01-25 19:04:24 UTC (rev 6858) @@ -66,15 +66,11 @@ <classpathentry exported="true" kind="lib" path="bigdata/lib/unimi/fastutil-5.1.5.jar"/> <classpathentry exported="true" kind="lib" path="bigdata/lib/lucene/lucene-analyzers-3.0.0.jar"/> <classpathentry exported="true" kind="lib" path="bigdata/lib/lucene/lucene-core-3.0.0.jar"/> - <classpathentry kind="lib" path="bigdata-rdf/lib/sesame-rio-testsuite-2.6.3.jar" sourcepath="/org.openrdf.sesame-2.6.3"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry exported="true" kind="lib" path="bigdata/lib/high-scale-lib-v1.1.2.jar"/> <classpathentry exported="true" kind="lib" path="bigdata/lib/junit-ext-1.1-b3-dev.jar"/> <classpathentry exported="true" kind="lib" path="bigdata-rdf/lib/slf4j-api-1.6.1.jar"/> <classpathentry exported="true" kind="lib" path="bigdata-rdf/lib/slf4j-log4j12-1.6.1.jar"/> - <classpathentry kind="lib" path="bigdata-rdf/lib/openrdf-sesame-2.6.3-onejar.jar" sourcepath="/Users/bryan/Documents/workspace/org.openrdf.sesame-2.6.3"/> - <classpathentry kind="lib" path="bigdata-sails/lib/sesame-sparql-testsuite-2.6.3.jar" sourcepath="/org.openrdf.sesame-2.6.3"/> - <classpathentry kind="lib" path="bigdata-sails/lib/sesame-store-testsuite-2.6.3.jar"/> <classpathentry kind="lib" path="bigdata-sails/lib/httpcomponents/commons-codec-1.4.jar"/> <classpathentry kind="lib" path="bigdata-sails/lib/httpcomponents/commons-logging-1.1.1.jar"/> <classpathentry kind="lib" path="bigdata-sails/lib/httpcomponents/httpclient-4.1.3.jar"/> @@ -84,5 +80,9 @@ <classpathentry kind="lib" path="bigdata-sails/lib/httpcomponents/commons-fileupload-1.2.2.jar"/> <classpathentry kind="lib" path="bigdata-sails/lib/httpcomponents/commons-io-2.1.jar"/> <classpathentry kind="lib" path="bigdata/lib/apache/log4j-1.2.17.jar"/> + <classpathentry kind="lib" path="bigdata-rdf/lib/openrdf-sesame-2.6.10-onejar.jar"/> + <classpathentry kind="lib" path="bigdata-rdf/lib/sesame-rio-testsuite-2.6.10.jar"/> + <classpathentry kind="lib" path="bigdata-sails/lib/sesame-sparql-testsuite-2.6.10.jar"/> + <classpathentry kind="lib" path="bigdata-sails/lib/sesame-store-testsuite-2.6.10.jar"/> <classpathentry kind="output" path="bin"/> </classpath> Property changes on: branches/READ_CACHE/bigdata/lib/jetty ___________________________________________________________________ Modified: svn:mergeinfo - /branches/INT64_BRANCH/bigdata/lib/jetty:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/lib/jetty:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/lib/jetty:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/lib/jetty:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/lib/jetty:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/lib/jetty:6766-6857 /branches/INT64_BRANCH/bigdata/lib/jetty:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/lib/jetty:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/lib/jetty:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/lib/jetty:4814-4836 Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bfs/BigdataFileSystem.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bfs/BigdataFileSystem.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bfs/BigdataFileSystem.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -410,15 +410,15 @@ } - final protected void assertWritable() { - - if(isReadOnly()) { - - throw new IllegalStateException("READ_ONLY"); - - } - - } +// final protected void assertWritable() { +// +// if(isReadOnly()) { +// +// throw new IllegalStateException("READ_ONLY"); +// +// } +// +// } /** * Note: A commit is required in order for a read-committed view to have Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/BOpUtility.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/BOpUtility.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/BOpUtility.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -1245,7 +1245,7 @@ // copy accepted binding sets to the default sink. sink.add(tmp); - nout += chunk.length; + nout += tmp.length; if (sink2 != null) { Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/Var.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/Var.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/Var.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -37,6 +37,20 @@ private static final long serialVersionUID = -7100443208125002485L; + private boolean anonymous = false; + + public void setAnonymous(boolean anonymous) { + + this.anonymous = anonymous; + + } + + public boolean isAnonymous() { + + return anonymous; + + } + final private String name; final public boolean isVar() { Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/aggregate ___________________________________________________________________ Modified: svn:mergeinfo - /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/aggregate:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/aggregate:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/aggregate:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/aggregate:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4814-4836 Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/controller/ServiceCallJoin.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/controller/ServiceCallJoin.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/controller/ServiceCallJoin.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -54,6 +54,7 @@ import com.bigdata.bop.join.JoinAnnotations; import com.bigdata.bop.join.JoinTypeEnum; import com.bigdata.htree.HTree; +import com.bigdata.rdf.lexicon.LexiconRelation; import com.bigdata.rdf.model.BigdataURI; import com.bigdata.rdf.sparql.ast.service.BigdataServiceCall; import com.bigdata.rdf.sparql.ast.service.ExternalServiceCall; @@ -774,8 +775,10 @@ final ServiceCall<BindingSet> serviceCall, final IBindingSet left[]) throws Exception { + final LexiconRelation lex = db.getLexiconRelation(); + // Convert IBindingSet[] to openrdf BindingSet[]. - final BindingSet[] left2 = ServiceCallUtility.convert( + final BindingSet[] left2 = ServiceCallUtility.convert(lex, projectedVars, left); /* Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/fed/QueryEngineFactory.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/fed/QueryEngineFactory.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/fed/QueryEngineFactory.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -38,8 +38,10 @@ import com.bigdata.bop.engine.QueryEngine; import com.bigdata.cache.ConcurrentWeakValueCache; import com.bigdata.journal.BufferMode; +import com.bigdata.journal.IBTreeManager; import com.bigdata.journal.IIndexManager; import com.bigdata.journal.Journal; +import com.bigdata.journal.TemporaryStore; import com.bigdata.relation.locator.IResourceLocator; import com.bigdata.service.DataService; import com.bigdata.service.IBigdataClient; @@ -66,7 +68,7 @@ * to keep any {@link QueryEngine} objects wired into the cache unless the * application is holding a hard reference to the {@link QueryEngine}. */ - private static ConcurrentWeakValueCache<Journal, QueryEngine> standaloneQECache = new ConcurrentWeakValueCache<Journal, QueryEngine>( + private static ConcurrentWeakValueCache<IBTreeManager, QueryEngine> standaloneQECache = new ConcurrentWeakValueCache<IBTreeManager, QueryEngine>( 0/* queueCapacity */ ); @@ -95,16 +97,16 @@ * and its weak reference has not been cleared. */ static public QueryEngine getExistingQueryController( - final IIndexManager indexManager) { + final IBTreeManager indexManager) { if (indexManager instanceof IBigdataFederation<?>) { return federationQECache.get((IBigdataFederation<?>) indexManager); } + // Note: Also supports TemporaryStore. + return standaloneQECache.get(indexManager); - return standaloneQECache.get((Journal)indexManager); - } /** @@ -122,21 +124,22 @@ return getFederatedQueryController((IBigdataFederation<?>) indexManager); } + // Note: Also supports TemporaryStore. + return getStandaloneQueryController((IBTreeManager) indexManager); - return getStandaloneQueryController((Journal) indexManager); - } /** * Singleton factory for standalone. * * @param indexManager - * The journal. - * + * The index manager. Can be a {@link TemporaryStore} or + * {@link Journal}. + * * @return The query controller. */ static public QueryEngine getStandaloneQueryController( - final Journal indexManager) { + final IBTreeManager indexManager) { if (indexManager == null) throw new IllegalArgumentException(); @@ -172,7 +175,7 @@ * @return The new query engine. */ private static QueryEngine newStandaloneQueryEngine( - final Journal indexManager) { + final IBTreeManager indexManager) { if (log.isInfoEnabled()) log.info("Initiallizing query engine: " + indexManager); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/join/PipelineJoin.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/join/PipelineJoin.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/join/PipelineJoin.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -64,6 +64,7 @@ import com.bigdata.relation.accesspath.ArrayAccessPath; import com.bigdata.relation.accesspath.BlockingBuffer; import com.bigdata.relation.accesspath.BufferClosedException; +import com.bigdata.relation.accesspath.EmptyAccessPath; import com.bigdata.relation.accesspath.IAccessPath; import com.bigdata.relation.accesspath.IAsynchronousIterator; import com.bigdata.relation.accesspath.IBindingSetAccessPath; @@ -1350,17 +1351,28 @@ */ final private IAccessPath<E> accessPath; - /** - * Return the <em>fromKey</em> for the {@link IAccessPath} generated - * from the {@link IBindingSet} for this task. - * - * @todo Layered access paths do not expose a fromKey, but the - * information we need is available - * {@link IKeyOrder#getFromKey(IKeyBuilder, IPredicate)}. - */ + /** + * Return the <em>fromKey</em> for the {@link IAccessPath} generated + * from the {@link IBindingSet} for this task. + * + * @todo Layered access paths do not expose a fromKey, but the + * information we need is available + * {@link IKeyOrder#getFromKey(IKeyBuilder, IPredicate)}. + * + * @see <a + * href="https://sourceforge.net/apps/trac/bigdata/ticket/631"> + * ClassCastException in SIDs mode query </a> + */ protected byte[] getFromKey() { - return ((AccessPath<E>) accessPath).getFromKey(); + if (accessPath instanceof EmptyAccessPath) { + + // EmptyAccessPath does not extend AccessPath. + return BytesUtil.EMPTY; + + } + + return ((AccessPath<E>) accessPath).getFromKey(); } Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/joinGraph ___________________________________________________________________ Modified: svn:mergeinfo - /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/joinGraph:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/joinGraph:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/joinGraph:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/joinGraph:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4814-4836 Deleted: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ArbitraryLengthPathOp.java =================================================================== --- branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/paths/ArbitraryLengthPathOp.java 2013-01-25 18:39:23 UTC (rev 6857) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/paths/ArbitraryLengthPathOp.java 2013-01-25 19:04:24 UTC (rev 6858) @@ -1,896 +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 -*/ -/* - * Created on Aug 18, 2010 - */ - -package com.bigdata.bop.paths; - -import java.util.Arrays; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; - -import org.apache.log4j.Logger; - -import com.bigdata.bop.BOp; -import com.bigdata.bop.BOpContext; -import com.bigdata.bop.IBindingSet; -import com.bigdata.bop.IConstant; -import com.bigdata.bop.IVariable; -import com.bigdata.bop.IVariableOrConstant; -import com.bigdata.bop.NV; -import com.bigdata.bop.PipelineOp; -import com.bigdata.bop.bindingSet.EmptyBindingSet; -import com.bigdata.bop.engine.AbstractRunningQuery; -import com.bigdata.bop.engine.IRunningQuery; -import com.bigdata.bop.engine.QueryEngine; -import com.bigdata.striterator.ICloseableIterator; - -/** - * Pipeline join incoming bindings against a special kind of subquery that - * represents an arbitrary length path between a single input variable and a - * single output variable. Continue this in rounds, using the output of the - * previous round as the input of the next round. This has the effect of - * producing the transitive closure of the subquery operation. - * <p> - * The basic idea behind this operator is to run a series of rounds until the - * solutions produced by each round reach a fixed point. Regardless of the the - * actual schematics of the arbitrary length path (whether there are constants - * or variables on the left and right side), we use two transitivity variables - * to keep the operator moving. Depending on the schematics of the arbitrary - * length path, we can run on forward (left side is input) or reverse (right - * side is input). For each intermediate solution, the binding for the - * transitivity variable on the output side is re-mapped to input for the next - * round. - * <p> - * This operator does not use internal parallelism, but it is thread-safe and - * multiple instances of this operator may be run in parallel by the query - * engine for parallel evaluation of different binding set chunks flowing - * through the pipeline. However, there are much more efficient query plan - * patterns for most use cases. E.g., (a) creating a hash index with all source - * solutions, (b) flooding a sub-section of the query plan with the source - * solutions from the hash index; and (c) hash joining the solutions from the - * sub-section of the query plan back against the hash index to reunite the - * solutions from the subquery with those in the parent context. - * - * @author <a href="mailto:mpe...@us...">Mike Personick</a> - */ -public class ArbitraryLengthPathOp extends PipelineOp { - - private static final Logger log = Logger.getLogger(ArbitraryLengthPathOp.class); - - /** - * - */ - private static final long serialVersionUID = 1L; - - public interface Annotations extends com.bigdata.bop.PipelineOp.Annotations { - - /** - * The subquery representing the path between left and right. - */ - String SUBQUERY = Annotations.class.getName() + ".subquery"; - - /** - * The left term - can be a variable or a constant. - */ - String LEFT_TERM = Annotations.class.getName() + ".leftTerm"; - - /** - * The right term - can be a variable or a constant. - */ - String RIGHT_TERM = Annotations.class.getName() + ".rightTerm"; - - /** - * The left transitivity variable. - */ - String TRANSITIVITY_VAR_LEFT = Annotations.class.getName() + ".transitivityVarLeft"; - - /** - * The right transitivity variable. - */ - String TRANSITIVITY_VAR_RIGHT = Annotations.class.getName() + ".transitivityVarRight"; - - /** - * The lower bound on the number of rounds to run. Can be zero (0) or - * one (1). A lower bound of zero is a special kind of path - the - * Zero Length Path. A zero length path connects a vertex to itself - * (in graph parlance). In the context of arbitrary length paths it - * means we bind the input onto the output regardless of whether they - * are actually connected via the path or not. - */ - String LOWER_BOUND = Annotations.class.getName() + ".lowerBound"; - - /** - * The upper bound on the number of rounds to run. - */ - String UPPER_BOUND = Annotations.class.getName() + ".upperBound"; - - /** - * Variables to dop in between rounds. This should be set to the - * internal variables produced by the path subquery. Each run of the - * subquery should be run "fresh", that is without its produced bindings - * already set. - */ - String VARS_TO_DROP = Annotations.class.getName() + ".varsToDrop"; - - } - - /** - * Deep copy constructor. - */ - public ArbitraryLengthPathOp(final ArbitraryLengthPathOp op) { - super(op); - } - - /** - * Shallow copy constructor. - * - * @param args - * @param annotations - */ - public ArbitraryLengthPathOp(final BOp[] args, - final Map<String, Object> annotations) { - - super(args, annotations); - - getRequiredProperty(Annotations.SUBQUERY); - - getRequiredProperty(Annotations.LEFT_TERM); - - getRequiredProperty(Annotations.RIGHT_TERM); - - getRequiredProperty(Annotations.TRANSITIVITY_VAR_LEFT); - - getRequiredProperty(Annotations.TRANSITIVITY_VAR_RIGHT); - - getRequiredProperty(Annotations.LOWER_BOUND); - - getRequiredProperty(Annotations.UPPER_BOUND); - - getRequiredProperty(Annotations.VARS_TO_DROP); - - } - - public ArbitraryLengthPathOp(final BOp[] args, NV... annotations) { - - this(args, NV.asMap(annotations)); - - } - - public FutureTask<Void> eval(final BOpContext<IBindingSet> context) { - - return new FutureTask<Void>(new ArbitraryLengthPathTask(this, context)); - - } - - private static class ArbitraryLengthPathTask implements Callable<Void> { - - private final BOpContext<IBindingSet> context; - private final PipelineOp subquery; - private final Gearing forwardGearing, reverseGearing; - private final long lowerBound, upperBound; - private IVariable<?>[] varsToDrop; - - public ArbitraryLengthPathTask(final ArbitraryLengthPathOp controllerOp, - final BOpContext<IBindingSet> context) { - - if (controllerOp == null) - throw new IllegalArgumentException(); - - if (context == null) - throw new IllegalArgumentException(); - - this.context = context; - - this.subquery = (PipelineOp) controllerOp - .getRequiredProperty(Annotations.SUBQUERY); - - final IVariableOrConstant<?> leftTerm = (IVariableOrConstant<?>) controllerOp - .getProperty(Annotations.LEFT_TERM); - - final IVariable<?> leftVar = leftTerm.isVar() ? (IVariable<?>) leftTerm : null; - - final IConstant<?> leftConst = leftTerm.isConstant() ? (IConstant<?>) leftTerm : null; - - final IVariableOrConstant<?> rightTerm = (IVariableOrConstant<?>) controllerOp - .getProperty(Annotations.RIGHT_TERM); - - final IVariable<?> rightVar = rightTerm.isVar() ? (IVariable<?>) rightTerm : null; - - final IConstant<?> rightConst = rightTerm.isConstant() ? (IConstant<?>) rightTerm : null; - - final IVariable<?> tVarLeft = (IVariable<?>) controllerOp - .getProperty(Annotations.TRANSITIVITY_VAR_LEFT); - - final IVariable<?> tVarRight = (IVariable<?>) controllerOp - .getProperty(Annotations.TRANSITIVITY_VAR_RIGHT); - - this.forwardGearing = new Gearing( - leftVar, rightVar, leftConst, rightConst, tVarLeft, tVarRight); - - this.reverseGearing = forwardGearing.reverse(); - - this.lowerBound = (Long) controllerOp - .getProperty(Annotations.LOWER_BOUND); - - this.upperBound = (Long) controllerOp - .getProperty(Annotations.UPPER_BOUND); - - this.varsToDrop = (IVariable<?>[]) controllerOp - .getProperty(Annotations.VARS_TO_DROP); - - } - - public Void call() throws Exception { - - try { - - final ICloseableIterator<IBindingSet[]> sitr = context - .getSource(); - - if (!sitr.hasNext()) { - - processChunk(new IBindingSet[0]); - - } else { - - while (sitr.hasNext()) { - - final IBindingSet[] chunk = sitr.next(); - - processChunk(chunk); - - } - - } - - // Now that we know the subqueries ran Ok, flush the sink. - context.getSink().flush(); - - // Done. - return null; - - } finally { - - context.getSource().close(); - - context.getSink().close(); - - if (context.getSink2() != null) - context.getSink2().close(); - - } - - } - - @SuppressWarnings("unchecked") - private void processChunk(final IBindingSet[] chunkIn) throws Exception { - - final Map<SolutionKey, IBindingSet> solutionsOut = - new LinkedHashMap<SolutionKey, IBindingSet>(); - - final QueryEngine queryEngine = this.context - .getRunningQuery().getQueryEngine(); - - /* - * The input to each round of transitive chaining. - */ - final Set<IBindingSet> nextRoundInput = new LinkedHashSet<IBindingSet>(); - - /* - * Decide based on the schematics of the path and the - * incoming data whether to run in forward or reverse gear. - * - * TODO Break the incoming chunk into two chunks - one to be run - * in forward gear and one to be run in reverse. This is an - * extremely unlikely scenario. - */ - final Gearing gearing = chooseGearing(chunkIn); - - if (log.isDebugEnabled()) { - log.debug("gearing: " + gearing); - } - - for (IBindingSet parentSolutionIn : chunkIn) { - - if (log.isDebugEnabled()) - log.debug("parent solution in: " + parentSolutionIn); - - IBindingSet childSolutionIn = parentSolutionIn.clone(); - - /* - * The seed is either a constant on the input side of - * the property path or a bound value for the property - * path's input variable from the incoming binding set. - */ - final IConstant<?> seed = gearing.inConst != null ? - gearing.inConst : childSolutionIn.get(gearing.inVar); - - if (log.isDebugEnabled()) - log.debug("seed: " + seed); - - if (seed != null) { - - childSolutionIn.set(gearing.tVarIn, seed); - - /* - * Dirty hack for zero length paths. Add a zero length - * path from the seed to itself. By handling this here - * (instead of in a separate operator) we get the - * cardinality right. Except in the case on nested - * arbitrary length paths, we are getting too few solutions - * from that (over-filtering). See the todo below. Again, - * this seems to be a very esoteric problem stemming from - * an unlikely scenario. Not going to fix it for now. - * - * TODO Add a binding for the bop id for the - * subquery that generated this solution and use - * that as part of the solution key somehow? This - * would allow duplicates from nested paths to - * remain in the outbound solutions, which seems to - * be the problem with the TCK query: - * - * :a (:p*)* ?y - */ - if (lowerBound == 0 && gearing.outVar != null && - !childSolutionIn.isBound(gearing.outVar)) { - - final IBindingSet bs = parentSolutionIn.clone(); - - /* - * Setting the outVar seems to produce duplicates - * when we do chunk at a time. - */ -// bs.set(gearing.outVar, seed); - - bs.set(gearing.tVarIn, seed); - - bs.set(gearing.tVarOut, seed); - - solutionsOut.put(newSolutionKey(gearing, bs), bs); - - if (log.isDebugEnabled()) { - log.debug("added a zero length path: " + bs); - } - - } - - } - - nextRoundInput.add(childSolutionIn); - - } - - if (log.isDebugEnabled()) { - for (IBindingSet childSolutionIn : nextRoundInput) - log.debug("first round input: " + childSolutionIn); - } - - for (int i = 0; i < upperBound; i++) { - - long sizeBefore = solutionsOut.size(); - - // The subquery - IRunningQuery runningSubquery = null; - // The iterator draining the subquery - ICloseableIterator<IBindingSet[]> subquerySolutionItr = null; - - try { - - runningSubquery = queryEngine.eval(subquery, - nextRoundInput.toArray(new IBindingSet[nextRoundInput.size()])); - - long count = 0L; - try { - - // Declare the child query to the parent. - ((AbstractRunningQuery) context.getRunningQuery()) - .addChild(runningSubquery); - - // clear the input set to make room for the next round - nextRoundInput.clear(); - - // Iterator visiting the subquery solutions. - subquerySolutionItr = runningSubquery.iterator(); - - while (subquerySolutionItr.hasNext()) { - - final IBindingSet[] chunk = subquerySolutionItr.next(); - - for (IBindingSet bs : chunk) { - - count++; - - if (log.isDebugEnabled()) { - log.debug("round " + i + " solution: " + bs); - } - - if (gearing.inVar != null && !bs.isBound(gearing.inVar)) { - - /* - * Must be the first round. The first - * round when there are no incoming - * binding (from the parent or previous - * rounds) is the only time the inVar - * won't be set. - */ - bs.set(gearing.inVar, bs.get(gearing.tVarIn)); - - if (log.isDebugEnabled()) { - log.debug("adding binding for inVar: " + bs); - } - - } - - // drop the intermediate variables - dropVars(bs); - -// solutionsOut.add(solution); - solutionsOut.put(newSolutionKey(gearing, bs), bs); - - /* - * Remap the solution as input to the next round. - */ - final IBindingSet input = bs.clone(); - - input.set(gearing.tVarIn, bs.get(gearing.tVarOut)); - - input.clear(gearing.tVarOut); - - nextRoundInput.add(input); - - if (log.isDebugEnabled()) { - log.debug("remapped as input for next round: " + input); - } - - } - - } - - // finished with the iterator - subquerySolutionItr.close(); - - // wait for the subquery to halt / test for errors. - runningSubquery.get(); - - if (log.isDebugEnabled()) { - log.debug("done with round " + i + - ", count=" + count + - ", totalBefore=" + sizeBefore + - ", totalAfter=" + solutionsOut.size() + - ", totalNew=" + (solutionsOut.size() - sizeBefore)); - } - - // we've reached fixed point - if (solutionsOut.size() == sizeBefore) { - - break; - - } - - } catch (InterruptedException ex) { - - // this thread was interrupted, so cancel the subquery. - runningSubquery - .cancel(true/* mayInterruptIfRunning */); - - // rethrow the exception. - throw ex; - - } - - } catch (Throwable t) { - - if (runningSubquery == null - || runningSubquery.getCause() != null) { - /* - * If things fail before we start the subquery, or if a - * subquery fails (due to abnormal termination), then - * propagate the error to the parent and rethrow the - * first cause error out of the subquery. - * - * Note: IHaltable#getCause() considers exceptions - * triggered by an interrupt to be normal termination. - * Such exceptions are NOT propagated here and WILL NOT - * cause the parent query to terminate. - */ - throw new RuntimeException(ArbitraryLengthPathTask.this.context - .getRunningQuery().halt( - runningSubquery == null ? t - : runningSubquery.getCause())); - } - -// return runningSubquery; - - } finally { - - try { - - // ensure subquery is halted. - if (runningSubquery != null) - runningSubquery - .cancel(true/* mayInterruptIfRunning */); - - } finally { - - // ensure the subquery solution iterator is closed. - if (subquerySolutionItr != null) - subquerySolutionItr.close(); - - } - - } - - } // fixed point for loop - - /* - * Do some final filtering and then send the solutions - * down the pipeline. - */ - final Iterator<Map.Entry<SolutionKey, IBindingSet>> it = - solutionsOut.entrySet().iterator(); - - while (it.hasNext()) { - - final Map.Entry<SolutionKey, IBindingSet> entry = it.next(); - - final IBindingSet bs = entry.getValue(); - - if (log.isDebugEnabled()) { - log.debug("considering possible solution: " + bs); - } - - if (gearing.outConst != null) { - - /* - * Handle the case where there is a constant on the - * output side of the subquery. Make sure the - * solution's transitive output variable matches. - */ - if (!bs.get(gearing.tVarOut).equals(gearing.outConst)) { - - if (log.isDebugEnabled()) { - log.debug("transitive output does not match output const, dropping"); - } - - it.remove(); - - continue; - - } - - } else { // outVar != null - - /* - * Handle the case where the gearing.outVar was bound - * coming in. Again, make sure it matches the - * transitive output variable. - */ - if (bs.isBound(gearing.outVar)) { - - if (!bs.get(gearing.tVarOut).equals(bs.get(gearing.outVar))) { - - if (log.isDebugEnabled()) { - log.debug("transitive output does not match incoming binding for output var, dropping"); - } - - it.remove(); - - continue; - - } - - } else { - - /* - ... [truncated message content] |
From: <tho...@us...> - 2013-02-06 01:07:43
|
Revision: 6890 http://bigdata.svn.sourceforge.net/bigdata/?rev=6890&view=rev Author: thompsonbry Date: 2013-02-06 01:07:30 +0000 (Wed, 06 Feb 2013) Log Message: ----------- Merging from dev branch to READ_CACHE branch to capture changes in the development branch. See [1] for the previous merge from the development branch to the READ_CACHE branch (which captured the delta from r6766 to r6857 of /branches/BIGDATA_RELEASE_1_2_0). {{{ At revision 6889. (Before doing the merge) merge https://bigdata.svn.sourceforge.net/svnroot/bigdata/branches/BIGDATA_RELEASE_1_2_0 /Users/bryan/Documents/workspace/BIGDATA_READ_CACHE_HEAD --- Merging r6857 through r6889 into /Users/bryan/Documents/workspace/BIGDATA_READ_CACHE_HEAD Merge complete. ===== File Statistics: ===== Deleted: 4 Added: 5 Updated: 43 No conflicts. }}} [1] https://sourceforge.net/apps/trac/bigdata/ticket/621 (Coalesce write cache records and install reads in cache) Revision Links: -------------- http://bigdata.svn.sourceforge.net/bigdata/?rev=6766&view=rev http://bigdata.svn.sourceforge.net/bigdata/?rev=6857&view=rev http://bigdata.svn.sourceforge.net/bigdata/?rev=6889&view=rev http://bigdata.svn.sourceforge.net/bigdata/?rev=6857&view=rev http://bigdata.svn.sourceforge.net/bigdata/?rev=6889&view=rev Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/solutions/SolutionSetStream.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractTask.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskBackedBufferStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IAtomicStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/JournalDelegate.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IRawStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/Allocator.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IAllocationManager.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IRWStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/PSOutputStream.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/sector/AllocationContext.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/sector/IMemoryManager.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/sector/MemStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/sector/MemStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/sector/MemoryManager.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/sector/PSInputStream.java branches/READ_CACHE/bigdata/src/java/com/bigdata/stream/Stream.java branches/READ_CACHE/bigdata/src/test/com/bigdata/btree/TestRawRecords.java branches/READ_CACHE/bigdata/src/test/com/bigdata/btree/TestRemoveAll.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestNamedIndices.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/TestWORMStrategy.java branches/READ_CACHE/bigdata/src/test/com/bigdata/rawstore/AbstractRawStoreTestCase.java branches/READ_CACHE/bigdata/src/test/com/bigdata/rwstore/TestRWJournal.java branches/READ_CACHE/bigdata/src/test/com/bigdata/rwstore/sector/TestMemoryManager.java branches/READ_CACHE/bigdata/src/test/com/bigdata/rwstore/sector/TestMemoryManagerStreams.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/eval/AST2BOpUtility.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/optimizers/ASTAttachJoinFiltersOptimizer.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/sparql/ast/optimizers/AbstractJoinGroupOptimizer.java branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/store/AbstractTripleStore.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/BigdataSail.java branches/READ_CACHE/bigdata-sails/src/test/org/openrdf/query/parser/sparql/ComplexSPARQLQueryTest.java Added Paths: ----------- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationContext.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationManagerStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IPSOutputStream.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IStreamStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/RawStoreDelegate.java Removed Paths: ------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IAllocationManagerStore.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IPSOutputStream.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IStreamStore.java Property Changed: ---------------- branches/READ_CACHE/ branches/READ_CACHE/bigdata/lib/jetty/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/aggregate/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/joinGraph/ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/util/ branches/READ_CACHE/bigdata/src/java/com/bigdata/htree/raba/ branches/READ_CACHE/bigdata/src/java/com/bigdata/jsr166/ branches/READ_CACHE/bigdata/src/test/com/bigdata/bop/joinGraph/ branches/READ_CACHE/bigdata/src/test/com/bigdata/bop/util/ branches/READ_CACHE/bigdata/src/test/com/bigdata/jsr166/ branches/READ_CACHE/bigdata/src/test/com/bigdata/util/httpd/ branches/READ_CACHE/bigdata-compatibility/ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/attr/ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/disco/ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/util/config/ branches/READ_CACHE/bigdata-perf/ branches/READ_CACHE/bigdata-perf/btc/ branches/READ_CACHE/bigdata-perf/btc/src/resources/ branches/READ_CACHE/bigdata-perf/lubm/ branches/READ_CACHE/bigdata-perf/uniprot/ branches/READ_CACHE/bigdata-perf/uniprot/src/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/bop/rdf/aggregate/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/changesets/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/error/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/internal/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/relation/ branches/READ_CACHE/bigdata-rdf/src/java/com/bigdata/rdf/util/ branches/READ_CACHE/bigdata-rdf/src/samples/ branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/bop/rdf/aggregate/ branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/internal/ branches/READ_CACHE/bigdata-rdf/src/test/com/bigdata/rdf/relation/ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/bench/ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/changesets/ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/ branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/bench/ branches/READ_CACHE/bigdata-sails/src/test/com/bigdata/rdf/sail/webapp/ branches/READ_CACHE/dsi-utils/ branches/READ_CACHE/dsi-utils/LEGAL/ branches/READ_CACHE/dsi-utils/lib/ branches/READ_CACHE/dsi-utils/src/ branches/READ_CACHE/dsi-utils/src/java/ branches/READ_CACHE/dsi-utils/src/java/it/ branches/READ_CACHE/dsi-utils/src/java/it/unimi/ branches/READ_CACHE/dsi-utils/src/test/ branches/READ_CACHE/dsi-utils/src/test/it/unimi/ branches/READ_CACHE/dsi-utils/src/test/it/unimi/dsi/ branches/READ_CACHE/lgpl-utils/src/java/it/unimi/dsi/fastutil/bytes/custom/ branches/READ_CACHE/lgpl-utils/src/test/it/unimi/dsi/fastutil/bytes/custom/ branches/READ_CACHE/osgi/ branches/READ_CACHE/src/resources/bin/config/ Property changes on: branches/READ_CACHE ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE:6769-6785 /branches/BIGDATA_RELEASE_1_2_0:6766-6857 /branches/BTREE_BUFFER_BRANCH:2004-2045 /branches/DEV_BRANCH_27_OCT_2009:2270-2546,2548-2782 /branches/INT64_BRANCH:4486-4522 /branches/JOURNAL_HA_BRANCH:2596-4066 /branches/LARGE_LITERALS_REFACTOR:4175-4387 /branches/LEXICON_REFACTOR_BRANCH:2633-3304 /branches/QUADS_QUERY_BRANCH:4525-4531,4550-4584,4586-4609,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH:4814-4836 /branches/bugfix-btm:2594-3237 /branches/dev-btm:2574-2730 /branches/fko:3150-3194 /trunk:3392-3437,3656-4061 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE:6769-6785 /branches/BIGDATA_RELEASE_1_2_0:6766-6889 /branches/BTREE_BUFFER_BRANCH:2004-2045 /branches/DEV_BRANCH_27_OCT_2009:2270-2546,2548-2782 /branches/INT64_BRANCH:4486-4522 /branches/JOURNAL_HA_BRANCH:2596-4066 /branches/LARGE_LITERALS_REFACTOR:4175-4387 /branches/LEXICON_REFACTOR_BRANCH:2633-3304 /branches/QUADS_QUERY_BRANCH:4525-4531,4550-4584,4586-4609,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH:4814-4836 /branches/bugfix-btm:2594-3237 /branches/dev-btm:2574-2730 /branches/fko:3150-3194 /trunk:3392-3437,3656-4061 Property changes on: branches/READ_CACHE/bigdata/lib/jetty ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/lib/jetty:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/lib/jetty:6766-6857 /branches/INT64_BRANCH/bigdata/lib/jetty:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/lib/jetty:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/lib/jetty:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/lib/jetty:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/lib/jetty:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/lib/jetty:6766-6889 /branches/INT64_BRANCH/bigdata/lib/jetty:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/lib/jetty:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/lib/jetty:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/lib/jetty:4814-4836 Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/aggregate ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/aggregate:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/aggregate:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/aggregate:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/aggregate:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/aggregate:6766-6889 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/aggregate:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/aggregate:4814-4836 Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/joinGraph ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/joinGraph:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/joinGraph:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/joinGraph:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/joinGraph:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/joinGraph:6766-6889 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/joinGraph:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/joinGraph:4814-4836 Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/solutions/SolutionSetStream.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/solutions/SolutionSetStream.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/solutions/SolutionSetStream.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -44,12 +44,12 @@ import com.bigdata.btree.Checkpoint; import com.bigdata.btree.IndexMetadata; import com.bigdata.io.SerializerUtil; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.rawstore.IRawStore; import com.bigdata.rdf.internal.encoder.SolutionSetStreamDecoder; import com.bigdata.rdf.internal.encoder.SolutionSetStreamEncoder; import com.bigdata.rdf.sparql.ast.ISolutionSetStats; import com.bigdata.rdf.sparql.ast.SolutionSetStats; -import com.bigdata.rwstore.IPSOutputStream; import com.bigdata.stream.Stream; import com.bigdata.striterator.Chunkerator; import com.bigdata.striterator.ICloseableIterator; Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/bop/util ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/util:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/util:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/util:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/util:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/util:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/util:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/bop/util:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/bop/util:6766-6889 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/bop/util:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/bop/util:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/bop/util:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/bop/util:4814-4836 Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/htree/raba ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/htree/raba:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/htree/raba:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/htree/raba:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/htree/raba:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/htree/raba:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/htree/raba:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/htree/raba:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/htree/raba:6766-6889 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/htree/raba:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/htree/raba:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/htree/raba:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/htree/raba:4814-4836 Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -401,14 +401,14 @@ * * 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]; - private final long[] addrsUsed = null; - private int addrsUsedCurs = 0; - private final char[] addrActions = null; - private final int[] addrLens = null; + // final long[] addrsUsed = new long[4024 * 1024]; + // private int addrsUsedCurs = 0; + // final char[] addrActions = new char[addrsUsed.length]; + // final int[] addrLens = new int[addrsUsed.length]; + private final long[] addrsUsed = null; + private int addrsUsedCurs = 0; + private final char[] addrActions = null; + private final int[] addrLens = null; /** * The backing reader that can be used when a cache read misses. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractBufferStrategy.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -23,7 +23,11 @@ */ package com.bigdata.journal; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.EOFException; import java.io.IOException; +import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; @@ -38,6 +42,8 @@ import com.bigdata.mdi.IResourceMetadata; import com.bigdata.rawstore.AbstractRawWormStore; import com.bigdata.rawstore.Bytes; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.rawstore.IRawStore; import com.bigdata.rawstore.WormAddressManager; import com.bigdata.resources.ResourceManager; @@ -180,6 +186,9 @@ */ final protected AtomicLong nextOffset; + /** The WORM address of the last committed allocation. */ + final protected AtomicLong commitOffset; + static final NumberFormat cf; static { @@ -269,6 +278,8 @@ this.nextOffset = new AtomicLong(nextOffset); + this.commitOffset = new AtomicLong(nextOffset); + this.bufferMode = bufferMode; this.open = true; @@ -601,17 +612,34 @@ } - /** The default is a NOP. */ + /** + * {@inheritDoc} + * <p> + * This implementation checks the current allocation offset with that in the + * rootBlock + * + * @return true if store has been modified since last commit() + */ @Override - public void commit() { + public boolean isDirty() { - // NOP for WORM. + return commitOffset.get() != nextOffset.get(); + } - /** The default is a NOP. */ + @Override + public void commit() { + + // remember offset at commit + commitOffset.set(nextOffset.get()); + + } + + @Override public void abort() { - // NOP + // restore the last committed value for nextOffset. + nextOffset.set(commitOffset.get()); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -29,6 +29,7 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.lang.ref.WeakReference; import java.net.InetSocketAddress; import java.nio.ByteBuffer; @@ -127,12 +128,14 @@ import com.bigdata.quorum.Quorum; import com.bigdata.quorum.QuorumActor; import com.bigdata.quorum.QuorumMember; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IAllocationManagerStore; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.rawstore.IRawStore; import com.bigdata.rawstore.SimpleMemoryRawStore; import com.bigdata.rawstore.WormAddressManager; import com.bigdata.relation.locator.IResourceLocator; import com.bigdata.resources.ResourceManager; -import com.bigdata.rwstore.IAllocationContext; import com.bigdata.rwstore.IAllocationManager; import com.bigdata.rwstore.IRWStrategy; import com.bigdata.rwstore.sector.MemStrategy; @@ -212,7 +215,7 @@ * been asynchronously closed. */ public abstract class AbstractJournal implements IJournal/* , ITimestampService */ -, IAllocationManager +, IAllocationManager, IAllocationManagerStore { /** @@ -2422,6 +2425,7 @@ } + @Override public void abort() { final WriteLock lock = _fieldReadWriteLock.writeLock(); @@ -2685,6 +2689,14 @@ // */ // abstract public AbstractLocalTransactionManager getLocalTransactionManager(); + @Override + public boolean isDirty() { + + return _bufferStrategy.isDirty(); + + } + + @Override public long commit() { final ILocalTransactionManager transactionManager = getLocalTransactionManager(); @@ -3265,6 +3277,36 @@ } + @Override + public IPSOutputStream getOutputStream() { + assertCanWrite(); + + return _bufferStrategy.getOutputStream(); + } + + @Override + public IPSOutputStream getOutputStream(final IAllocationContext context) { + + assertCanWrite(); + + if (_bufferStrategy instanceof IRWStrategy) { + + return ((IRWStrategy) _bufferStrategy).getOutputStream(context); + + } else { + + return _bufferStrategy.getOutputStream(); + + } + + } + + @Override + public InputStream getInputStream(long addr) { + return _bufferStrategy.getInputStream(addr); + } + + // Note: NOP for WORM. Used by RW for eventual recycle protocol. public void delete(final long addr) { @@ -5977,5 +6019,4 @@ return removed; } - } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractTask.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractTask.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractTask.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -29,6 +29,7 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.HashMap; @@ -64,6 +65,8 @@ import com.bigdata.concurrent.NonBlockingLockManager; import com.bigdata.counters.CounterSet; import com.bigdata.mdi.IResourceMetadata; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.relation.locator.DefaultResourceLocator; import com.bigdata.relation.locator.ILocatableResource; import com.bigdata.relation.locator.IResourceLocator; @@ -71,7 +74,6 @@ import com.bigdata.resources.ResourceManager; import com.bigdata.resources.StaleLocatorException; import com.bigdata.resources.StaleLocatorReason; -import com.bigdata.rwstore.IAllocationContext; import com.bigdata.rwstore.IRWStrategy; import com.bigdata.rwstore.IRawTx; import com.bigdata.sparse.GlobalRowStoreHelper; @@ -2660,7 +2662,18 @@ // return delegate.write(data, oldAddr, this); // } - public void delete(final long addr) { + + @Override + public IPSOutputStream getOutputStream() { + return delegate.getOutputStream(this); + } + + @Override + public InputStream getInputStream(long addr) { + return delegate.getInputStream(addr); + } + + public void delete(final long addr) { delegate.delete(addr, this); } @@ -2708,6 +2721,11 @@ throw new UnsupportedOperationException(); } + @Override + public boolean isDirty() { + return delegate.isDirty(); + } + } // class IsolatatedActionJournal /** @@ -3155,6 +3173,20 @@ return delegate.getHttpdPort(); } + @Override + public IPSOutputStream getOutputStream() { + throw new UnsupportedOperationException(); + } + + @Override + public InputStream getInputStream(long addr) { + return delegate.getInputStream(addr); + } + + @Override + public boolean isDirty() { + return false; // it's readOnly - cannot be dirty + } } // class ReadOnlyJournal /** Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskBackedBufferStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskBackedBufferStrategy.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskBackedBufferStrategy.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -25,12 +25,15 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import com.bigdata.io.FileChannelUtility; import com.bigdata.io.IReopenChannel; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IPSOutputStream; /** * Abstract base class for implementations that use a direct buffer as a write @@ -430,4 +433,5 @@ public void setNextOffset(long lastOffset) { // void for default DiskBackedBufferStrategy } + } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DiskOnlyStrategy.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -485,11 +485,12 @@ */ @Override public void commit() { - if (writeCache != null) { - synchronized(this) { - flushWriteCache(); - } - } + if (writeCache != null) { + synchronized (this) { + flushWriteCache(); + } + } + super.commit(); } /** Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IAtomicStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IAtomicStore.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IAtomicStore.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -62,6 +62,15 @@ public long commit(); /** + * Return <code>true</code> if the store has been modified since the last + * {@link #commit()} or {@link #abort()}. + * + * @return true if store has been modified since last {@link #commit()} or + * {@link #abort()}. + */ + public boolean isDirty(); + + /** * Set a persistence capable data structure for callback during the commit * protocol. * <p> Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IBufferStrategy.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -231,6 +231,15 @@ public void abort(); /** + * Return <code>true</code> if the store has been modified since the last + * {@link #commit()} or {@link #abort()}. + * + * @return true if store has been modified since last {@link #commit()} or + * {@link #abort()}. + */ + public boolean isDirty(); + + /** * 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. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/JournalDelegate.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/JournalDelegate.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/JournalDelegate.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -25,6 +25,7 @@ package com.bigdata.journal; import java.io.File; +import java.io.InputStream; import java.nio.ByteBuffer; import java.util.Iterator; import java.util.Properties; @@ -39,6 +40,8 @@ import com.bigdata.btree.IndexMetadata; import com.bigdata.counters.CounterSet; import com.bigdata.mdi.IResourceMetadata; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.relation.locator.IResourceLocator; import com.bigdata.sparse.SparseRowStore; @@ -269,4 +272,19 @@ public Iterator<String> indexNameScan(String prefix, long timestamp) { return delegate.indexNameScan(prefix, timestamp); } + + @Override + public IPSOutputStream getOutputStream() { + return delegate.getOutputStream(); + } + + @Override + public InputStream getInputStream(long addr) { + return delegate.getInputStream(addr); + } + + @Override + public boolean isDirty() { + return delegate.isDirty(); + } } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RWStrategy.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -48,8 +48,8 @@ import com.bigdata.quorum.Quorum; import com.bigdata.rawstore.AbstractRawStore; import com.bigdata.rawstore.IAddressManager; -import com.bigdata.rwstore.IAllocationContext; -import com.bigdata.rwstore.IPSOutputStream; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.rwstore.IRWStrategy; import com.bigdata.rwstore.IRawTx; import com.bigdata.rwstore.RWStore; @@ -446,6 +446,7 @@ /** * Calls through to store and then to WriteCacheService.reset */ + @Override public void abort() { m_store.reset(); @@ -569,7 +570,18 @@ } - public long getMetaBitsAddr() { + /** + * Supports protocol in BigdataSailConnection to check for modifications + * prior to calling rollback(). + * + * @return true if store has been modified since last commit() + */ + @Override + public boolean isDirty() { + return m_store.requiresCommit(); + } + + public long getMetaBitsAddr() { return m_store.getMetaBitsAddr(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -23,14 +23,19 @@ */ package com.bigdata.journal; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.EOFException; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.FileChannel; import java.security.DigestException; import java.security.MessageDigest; +import java.util.ArrayList; import java.util.Map; import java.util.UUID; import java.util.concurrent.Future; @@ -63,6 +68,8 @@ import com.bigdata.io.writecache.WriteCacheCounters; import com.bigdata.io.writecache.WriteCacheService; import com.bigdata.quorum.Quorum; +import com.bigdata.rawstore.IAllocationContext; +import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.rawstore.IRawStore; import com.bigdata.util.ChecksumError; import com.bigdata.util.ChecksumUtility; @@ -1152,9 +1159,11 @@ } + super.commit(); + } - @Override + @Override public long getBlockSequence() { return lastBlockSequence; @@ -1172,6 +1181,8 @@ @Override public void abort() { + super.abort(); + if (writeCacheService != null) { try { if (quorum != null) { @@ -1196,7 +1207,7 @@ throw new RuntimeException(e); } } - + } /** @@ -2549,7 +2560,9 @@ @Override public void resetFromHARootBlock(final IRootBlockView rootBlock) { - nextOffset.set(rootBlock.getNextOffset()); + final long rbNextOffset = rootBlock.getNextOffset(); + nextOffset.set(rbNextOffset); + commitOffset.set(rbNextOffset); } @@ -2653,7 +2666,6 @@ } } - @Override public void writeRawBuffer(HARebuildRequest req, IHAWriteMessage msg, ByteBuffer transfer) throws IOException { Property changes on: branches/READ_CACHE/bigdata/src/java/com/bigdata/jsr166 ___________________________________________________________________ Modified: svn:mergeinfo - /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/jsr166:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/jsr166:6766-6857 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/jsr166:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/jsr166:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/jsr166:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/jsr166:4814-4836 + /branches/BIGDATA_OPENRDF_2_6_9_UPDATE/bigdata/src/java/com/bigdata/jsr166:6769-6785 /branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/jsr166:6766-6889 /branches/INT64_BRANCH/bigdata/src/java/com/bigdata/jsr166:4486-4522 /branches/QUADS_QUERY_BRANCH/bigdata/src/java/com/bigdata/jsr166:4525-4531,4533-4548,4550-4584,4586-4609,4611-4632,4634-4643,4646-4672,4674-4685,4687-4693,4697-4735,4737-4782,4784-4792,4794-4796,4798-4801 /branches/RWSTORE_1_1_0_DEBUG/bigdata/src/java/com/bigdata/jsr166:5896-5935 /branches/TIDS_PLUS_BLOBS_BRANCH/bigdata/src/java/com/bigdata/jsr166:4814-4836 Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/AbstractRawStore.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -27,6 +27,10 @@ package com.bigdata.rawstore; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.nio.ByteBuffer; import com.bigdata.LRUNexus; @@ -78,30 +82,233 @@ // NOP. } -// public void delete(long addr, IAllocationContext context) { -// delete(addr); -// } -// -// public long write(ByteBuffer data, IAllocationContext context) { -// return write(data); -// } -// -// public long write(ByteBuffer data, long oldAddr, IAllocationContext context) { -// return write(data, oldAddr); -// } -// -// /** -// * The default implementation is a NOP. -// */ -// public void detachContext(IAllocationContext context) { -// // NOP -// } -// -// /** -// * The default implementation is a NOP. -// */ -// public void abortContext(final IAllocationContext context) { -// // NOP -// } - + @Override + public IPSOutputStream getOutputStream() { + // TODO: implement an optional pooled object creation + // to allow re-use of streams (with their buffers). + // see ticket:#641 + return new WORMOutputStream(); + } + + @Override + public InputStream getInputStream(long addr) { + return new WORMInputStream(addr); + } + + // WORM_STREAM_BUFFER_SIZE as used by Output and Input streams + static final int WORM_STREAM_BUFFER_SIZE = 16 * 1024; + + /** + * WORMOutputStream + * <p> + * This implements a buffered allocation that may be split + * across muliple smaller allocations, thus providing a scalable + * approach for concurrent allocations of very large amounts + * of data without needing single large buffers for the full + * amount. + * <p> + * The stream address may be interpreted differently from a normal + * allocation in that the data size is associated with the total data + * stored across all stream allocations. Thus an address returned by + * a stream must only ever be used to retrieve an input stream. + * <p> + * This is different from the RWStore where the BLOB allocation mechanism + * uses streams internally and therefore the addressing mechanism is + * compatible with external stream usage. + * <p> + * Note that an address returned from getAddr() is the negative of the + * normal storage address, differentiating a stream address from a + * conventional allocation. + */ + class WORMOutputStream extends IPSOutputStream { + final private byte[] m_buffer = new byte[WORM_STREAM_BUFFER_SIZE]; + private int m_cursor = 0; + + private int m_bytesWritten = 0; + + private boolean m_open = true; // open on creation + + private ByteArrayOutputStream m_hdrData = null; + private DataOutputStream m_header = null; + + @Override + public long getAddr() { + if (!m_open) + throw new IllegalStateException(); + + m_open = false; + + if (m_cursor == 0) + return 0; // no content is fine for a stream + + final ByteBuffer bb = ByteBuffer.wrap(m_buffer, 0, m_cursor); + + final long addr = AbstractRawStore.this.write(bb); + + m_bytesWritten += m_cursor; + + if (m_header == null) + return addr; // return conventional address since no header is required + + // handle blob stream header + try { + m_header.writeLong(addr); + } catch (IOException e) { + throw new RuntimeException(e); + } + + + // write stream header + final ByteBuffer hbb = ByteBuffer.wrap(m_hdrData.toByteArray()); + final long hdrAddr = AbstractRawStore.this.write(hbb); + + final IAddressManager am = getAddressManager(); + + // return a stream address indicating the total size of the data and the address + // of the header data. + // + // the negative address indicates that this is a stream header and cannot be + // processed as a contiguous allocation. + // + // FIXME: enable standard non-stream read to process streamed data similarly to + // RWStore BLOB handling. + return -am.toAddr(m_bytesWritten, am.getOffset(hdrAddr)); + } + + @Override + public void write(int b) throws IOException { + // check threshold write + if (m_cursor == WORM_STREAM_BUFFER_SIZE) { + final ByteBuffer bb = ByteBuffer.wrap(m_buffer); + final long waddr = AbstractRawStore.this.write(bb); + if (m_header == null) { + m_hdrData = new ByteArrayOutputStream(); + m_header = new DataOutputStream(m_hdrData); + } + m_header.writeLong(waddr); + m_cursor = 0; + m_bytesWritten += WORM_STREAM_BUFFER_SIZE; + } + + m_buffer[m_cursor++] = (byte) b; + } + + /**************************************************************** + * write byte array to the buffer + * + * we need to be able to efficiently handle large arrays beyond size + * of the blobThreshold, so + **/ + public void write(final byte b[], final int off, final int len) throws IOException { + + if (!m_open) { + throw new IllegalStateException("Already written"); + } + + if ((m_cursor + len) > WORM_STREAM_BUFFER_SIZE) { + // not optimal, but this will include a disk write anyhow so who cares + for (int i = 0; i < len; i++) { + write(b[off+i]); + } + } else { + System.arraycopy(b, off, m_buffer, m_cursor, len); + + m_cursor += len; + + } + } + } + + /** + * The WORMInputStream is returned by the getInputStream + * method. + * + * + */ + class WORMInputStream extends InputStream { + + final private ByteBuffer m_hbb; + private ByteBuffer m_bb; + + WORMInputStream(final long stream_addr) { +// if (stream_addr > 0) { +// throw new IllegalArgumentException("Address: " + stream_addr + " was not returned from a stream"); +// } + + // if negative then is a stream header + final boolean isStream = stream_addr < 0; + + // convert back to original allocation adress + final long addr = isStream ? -stream_addr : stream_addr; + + final IAddressManager am = getAddressManager(); + + final int nbytes = am.getByteCount(addr); + + // Stream could have + if (isStream && nbytes != 0 && nbytes < WORM_STREAM_BUFFER_SIZE) + throw new IllegalArgumentException("Stream Address for unexpected data length: " + nbytes); + + // check for stream header + if (isStream) { + // handle overspill + final int nblocks = (nbytes + (WORM_STREAM_BUFFER_SIZE-1)) / WORM_STREAM_BUFFER_SIZE; + + m_hbb = AbstractRawStore.this.read(am.toAddr(nblocks * 8, am.getOffset(addr))); // 8 bytes size of long + + // read first block + assert m_hbb.hasRemaining(); + m_bb = AbstractRawStore.this.read(m_hbb.getLong()); + } else { + m_hbb = null; + + if (nbytes > 0) + m_bb = AbstractRawStore.this.read(addr); + else + m_bb = ByteBuffer.allocate(0); + } + } + + @Override + public int read() throws IOException { + if (!m_bb.hasRemaining() && m_hbb != null && m_hbb.hasRemaining()) { + m_bb = AbstractRawStore.this.read(m_hbb.getLong()); + } + + if (!m_bb.hasRemaining()) + return -1; + + // return unsigned byte as int + return 0xFF & m_bb.get(); + } + + public synchronized int read(final byte dst[], final int off, final int len) throws IOException { + if (m_bb.remaining() >= len) { + m_bb.get(dst, off, len); + return len; + } + int cursor = 0; + + final int len1 = m_bb.remaining(); + m_bb.get(dst, off, len1); + cursor += len1; + + while (m_hbb != null && m_hbb.hasRemaining()) { + m_bb = AbstractRawStore.this.read(m_hbb.getLong()); + + final int len2 = len - cursor; + if (m_bb.remaining() >= len2) { + m_bb.get(dst, off+cursor, len2); + cursor += len2; + break; + } else { + final int len3 = m_bb.remaining(); + m_bb.get(dst, off+cursor, len3); + cursor += len3; + } + } + + return cursor; + } + } } Copied: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationContext.java (from rev 6889, branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/rawstore/IAllocationContext.java) =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationContext.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationContext.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -0,0 +1,35 @@ +/** + +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.rawstore; + +/** + * An {@link IAllocationContext} defines a shadow environment which may be + * associated with allocations made during a transaction. + * + * @author Martyn Cutcher + */ +public interface IAllocationContext { + +} Copied: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationManagerStore.java (from rev 6889, branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/rawstore/IAllocationManagerStore.java) =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationManagerStore.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IAllocationManagerStore.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -0,0 +1,81 @@ +/** + +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.rawstore; + +import java.nio.ByteBuffer; + +import com.bigdata.rwstore.IAllocationManager; + +/** + * Adds capability to write and delete allocations within an + * {@link IAllocationContext}. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * + * @see IAllocationManager + * @see IAllocationContext + */ +public interface IAllocationManagerStore extends IStreamStore { + + /** + * Write the data within the allocation context. The write is not visible + * outside of the allocation until the allocation context has been merged + * into the parent allocation context. + * + * @param data + * The data. + * @param context + * The allocation context. + * + * @return The address at which the data was written. + */ + long write(ByteBuffer data, IAllocationContext context); + + /** + * Delete the data associated with the address within the allocation + * context. The delete is not visible outside of the allocation until the + * allocation context has been merged into the parent allocation context. + * + * @param addr + * The address whose allocation is to be deleted. + * @param context + * The allocation context. + */ + void delete(long addr, IAllocationContext context); + + /** + * Return an output stream which can be used to write on the backing store + * within the given allocation context. You can recover the address used to + * read back the data from the {@link IPSOutputStream}. + * + * @param context + * The context within which any allocations are made by the + * returned {@link IPSOutputStream}. + * + * @return an output stream to stream data to and to retrieve an address to + * later stream the data back. + */ + public IPSOutputStream getOutputStream(final IAllocationContext context); + +} Copied: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IPSOutputStream.java (from rev 6889, branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/rawstore/IPSOutputStream.java) =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IPSOutputStream.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IPSOutputStream.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -0,0 +1,23 @@ +package com.bigdata.rawstore; + +import java.io.OutputStream; + +/** + * This class provides a stream-based allocation mechanism. + * <p> + * The intention is that an IPSOutputStream (PS for PerSistent) is + * returned by a storage service to which data can be written. + * When all data has been written the address from which to retriev + * an InputStream can be requested. + * + * @author Martyn Cutcher + * + */ +public abstract class IPSOutputStream extends OutputStream { + + /** + * Called when writes to the stream are complete. + * @return the address from which an InputStream can be retrieved. + */ + public abstract long getAddr(); +} Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IRawStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IRawStore.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IRawStore.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -86,7 +86,7 @@ * . * */ -public interface IRawStore extends IAddressManager, ICounterSetAccess { +public interface IRawStore extends IAddressManager, ICounterSetAccess, IStreamStore { /** * Write the data (unisolated). Copied: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IStreamStore.java (from rev 6889, branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/rawstore/IStreamStore.java) =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IStreamStore.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/IStreamStore.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -0,0 +1,56 @@ +/** + +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.rawstore; + +import java.io.InputStream; + + +/** + * Interface for reading and writing streams on a persistence store. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public interface IStreamStore { + + /** + * Return an output stream which can be used to write on the backing store. + * You can recover the address used to read back the data from the + * {@link IPSOutputStream}. + * + * @return The output stream. + */ + public IPSOutputStream getOutputStream(); + + /** + * Return an input stream from which a previously written stream may be read + * back. + * + * @param addr + * The address at which the stream was written. + * + * @return an input stream for the data for provided address + */ + public InputStream getInputStream(long addr); + +} Copied: branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/RawStoreDelegate.java (from rev 6889, branches/BIGDATA_RELEASE_1_2_0/bigdata/src/java/com/bigdata/rawstore/RawStoreDelegate.java) =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/RawStoreDelegate.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rawstore/RawStoreDelegate.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -0,0 +1,162 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. 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.rawstore; + +import java.io.File; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.UUID; + +import com.bigdata.counters.CounterSet; +import com.bigdata.mdi.IResourceMetadata; + +/** + * Simple delegation pattern. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public class RawStoreDelegate implements IRawStore { + + protected final IRawStore delegate; + + public RawStoreDelegate(final IRawStore delegate) { + this.delegate = delegate; + } + + @Override + public void close() { + delegate.close(); + } + + @Override + public void delete(long addr) { + delegate.delete(addr); + } + + @Override + public void deleteResources() { + delegate.deleteResources(); + } + + @Override + public void destroy() { + delegate.destroy(); + } + + @Override + public void force(boolean metadata) { + delegate.force(metadata); + } + + @Override + public int getByteCount(long addr) { + return delegate.getByteCount(addr); + } + + @Override + public CounterSet getCounters() { + return delegate.getCounters(); + } + + @Override + public File getFile() { + return delegate.getFile(); + } + + @Override + public long getOffset(long addr) { + return delegate.getOffset(addr); + } + + @Override + public long getPhysicalAddress(final long addr) { + return delegate.getPhysicalAddress(addr); + } + + @Override + public IResourceMetadata getResourceMetadata() { + return delegate.getResourceMetadata(); + } + + @Override + public UUID getUUID() { + return delegate.getUUID(); + } + + @Override + public boolean isFullyBuffered() { + return delegate.isFullyBuffered(); + } + + @Override + public boolean isOpen() { + return delegate.isOpen(); + } + + @Override + public boolean isReadOnly() { + return delegate.isReadOnly(); + } + + @Override + public boolean isStable() { + return delegate.isStable(); + } + + @Override + public ByteBuffer read(long addr) { + return delegate.read(addr); + } + + @Override + public long size() { + return delegate.size(); + } + + @Override + public long toAddr(int nbytes, long offset) { + return delegate.toAddr(nbytes, offset); + } + + @Override + public String toString(long addr) { + return delegate.toString(addr); + } + + @Override + public long write(ByteBuffer data) { + return delegate.write(data); + } + + @Override + public IPSOutputStream getOutputStream() { + return delegate.getOutputStream(); + } + + @Override + public InputStream getInputStream(long addr) { + return delegate.getInputStream(addr); + } + +} Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/Allocator.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/Allocator.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/Allocator.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicLong; +import com.bigdata.rawstore.IAllocationContext; import com.bigdata.rwstore.RWStore.AllocationStats; Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/FixedAllocator.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -31,6 +31,7 @@ import org.apache.log4j.Logger; +import com.bigdata.rawstore.IAllocationContext; import com.bigdata.rwstore.RWStore.AllocationStats; import com.bigdata.rwstore.StorageStats.Bucket; import com.bigdata.util.ChecksumUtility; Deleted: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java 2013-02-06 00:51:42 UTC (rev 6889) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/IAllocationContext.java 2013-02-06 01:07:30 UTC (rev 6890) @@ -1,35 +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 Pu... [truncated message content] |
From: <tho...@us...> - 2013-02-08 16:17:56
|
Revision: 6896 http://bigdata.svn.sourceforge.net/bigdata/?rev=6896&view=rev Author: thompsonbry Date: 2013-02-08 16:17:49 +0000 (Fri, 08 Feb 2013) Log Message: ----------- Fixed bug in awaitCondition() where it would only wait for an AssertionFailedError but not a TimeoutException. It now waits up to the timeout for anything. Added in code for handling the quorum break to HAJournalServer. Added HA2 test suite into CI. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/TestCase3.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestAll.java Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/TestCase3.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/TestCase3.java 2013-02-08 15:37:38 UTC (rev 6895) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/TestCase3.java 2013-02-08 16:17:49 UTC (rev 6896) @@ -30,13 +30,13 @@ import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; -import com.bigdata.btree.BytesUtil; -import com.bigdata.journal.TestHelper; - import junit.framework.AssertionFailedError; import junit.framework.TestCase; import junit.framework.TestCase2; +import com.bigdata.btree.BytesUtil; +import com.bigdata.journal.TestHelper; + /** * Base class for some <code>assertEquals</code> methods not covered by * {@link TestCase} or {@link TestCase2}. @@ -204,11 +204,14 @@ cond.run(); // success. return; - } catch (final AssertionFailedError e) { + } catch (final Throwable e) { +// final boolean interesting = // +// InnerCause.isInnerCause(e, AssertionFailedError.class) || // +// InnerCause.isInnerCause(e, TimeoutException.class); remaining = nanos - (System.nanoTime() - begin); if (remaining < 0) { // Timeout - rethrow the failed assertion. - throw e; + throw new RuntimeException(e); } // Sleep up to 10ms or the remaining nanos, which ever is less. final int millis = (int) Math.min( @@ -225,7 +228,7 @@ remaining = nanos - (System.nanoTime() - begin); if (remaining < 0) { // Timeout - rethrow the failed assertion. - throw e; + throw new RuntimeException(e); } } } Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-08 15:37:38 UTC (rev 6895) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-08 16:17:49 UTC (rev 6896) @@ -824,19 +824,19 @@ } - // if (server.isRunning()) { - // /* - // * Attempt to cast a vote for our lastCommitTime. - // * - // * FIXME BOUNCE : May need to trigger when we re-connect with - // * zookeeper if this event was triggered by a zk session - // * expiration. - // */ - // doConditionalCastVote(server, - // (Quorum<HAGlue, QuorumService<HAGlue>>) this - // .getQuorum(), - // journal); - // } + if (server.isRunning()) { + /* + * Attempt to cast a vote for our lastCommitTime. + * + * FIXME BOUNCE : May need to trigger when we re-connect + * with zookeeper if this event was triggered by a zk + * session expiration. + */ + doConditionalCastVote( + server, + (Quorum<HAGlue, QuorumService<HAGlue>>) getQuorum(), + journal); + } // Done. return null; Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestAll.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestAll.java 2013-02-08 15:37:38 UTC (rev 6895) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestAll.java 2013-02-08 16:17:49 UTC (rev 6896) @@ -86,7 +86,7 @@ // HA2 test suite (k=3, but only 2 services are running). // FIXME (***) Enable TestHA2JournalServer in CI (debug bounce leader/follower first). - //suite.addTestSuite(TestHA2JournalServer.class); + suite.addTestSuite(TestHA2JournalServer.class); // HA3 test suite. suite.addTestSuite(TestHA3JournalServer.class); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-15 16:13:47
|
Revision: 6902 http://bigdata.svn.sourceforge.net/bigdata/?rev=6902&view=rev Author: thompsonbry Date: 2013-02-15 16:13:35 +0000 (Fri, 15 Feb 2013) Log Message: ----------- Exposed AbstractJournal.getQuourmToken() to the HAJournalServer. Added HALogWriter.isOpen(). Javadoc on AbstractQuorumClient. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorumClient.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-14 19:18:18 UTC (rev 6901) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-15 16:13:35 UTC (rev 6902) @@ -158,6 +158,10 @@ throw new IllegalStateException(); } + + public boolean isOpen() { + return m_state != null; + } /** * Return the log file (if any). Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-14 19:18:18 UTC (rev 6901) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-15 16:13:35 UTC (rev 6902) @@ -4817,7 +4817,7 @@ */ private volatile long quorumToken = Quorum.NO_QUORUM; - protected final long getQuorumToken() { + protected long getQuorumToken() { return quorumToken; Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorumClient.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorumClient.java 2013-02-14 19:18:18 UTC (rev 6901) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorumClient.java 2013-02-15 16:13:35 UTC (rev 6902) @@ -64,6 +64,13 @@ } + /** + * {@inheritDoc} + * <p> + * + * @return The reference from an atomic variable that will be cleared if the + * quorum terminates. + */ public Quorum<?,?> getQuorum() { final Quorum<?,?> tmp = quorum.get(); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-14 19:18:18 UTC (rev 6901) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-15 16:13:35 UTC (rev 6902) @@ -395,7 +395,19 @@ } + /** + * {@inheritDoc} + * <p> + * Overridden to expose this method to the {@link HAJournalServer}. + */ @Override + protected final long getQuorumToken() { + + return super.getQuorumToken(); + + } + + @Override public final File getHALogDir() { return haLogDir; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-19 15:34:39
|
Revision: 6910 http://bigdata.svn.sourceforge.net/bigdata/?rev=6910&view=rev Author: thompsonbry Date: 2013-02-19 15:34:29 +0000 (Tue, 19 Feb 2013) Log Message: ----------- I have pulled out the logic to create the root blocks from FileMetadata into RootBlockUtility. We need to install empty root blocks at the top of REBUILD to prevent interpretation of the backing file if there is a service restart. I also removed the essentially unused fields rootBlock0 and rootBlock1 on FileMetadata. They were only set along one code path and never referenced again in the code base. Modified sendHAStore() to return the then current root block once the file send is done. Renamed installRootBlocksQuorum() to installRootBlocks() since since we need to do this at the top of rebuild using new root blocks NOT from the quorum to make the store logically empty. @see https://sourceforge.net/apps/trac/bigdata/ticket/530 (Journal HA) Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/FileMetadata.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -200,7 +200,8 @@ } @Override - public Future<Void> sendHAStore(IHARebuildRequest msg) throws IOException { + public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + throws IOException { return delegate.sendHAStore(msg); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -37,6 +37,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHARootBlockResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -206,9 +207,12 @@ * A request to replicate a backing store. * * @return A {@link Future} that may be used to cancel the remote process - * sending the data through the write pipeline. + * sending the data through the write pipeline. The {@link Future} + * will report the current root block in effect as of the moment + * when the <code>sendHAStore</code> operation was completed. */ - Future<Void> sendHAStore(IHARebuildRequest msg) throws IOException; + Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + throws IOException; // /** // * There is something for this on HAGlue right now. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -92,7 +92,19 @@ long getPrepareTimeout(); /** - * Install the root blocks from the quorum on the local service. + * Install identical root blocks on the local service. This is used for a + * few different conditions in HA. + * <ol> + * <li>When the quorum meets for the first time, we need to take the root + * block from the leader and use it to replace both of our root blocks (the + * initial root blocks are identical). That will make the root blocks the + * same on all quorum members.</li> + * <li>REBUILD: When a service goes through an automated disaster recovery, + * we need to install new root blocks in order to make the local journal + * logically empty. This prevents the service from attempting to interpret + * the data on the backing file if there is a restart part way through the + * rebuild operation.</li> + * </ol> * <p> * Note: The initial root blocks on a service are identical, so this root * block will be installed as both root block ZERO (0) and root block ONE @@ -100,10 +112,7 @@ * * @param rootBlock * The root block. - * - * @throws IllegalStateException - * if the local service already has writes. */ - void installRootBlocksFromQuorum(final IRootBlockView rootBlock); + void installRootBlocks(final IRootBlockView rootBlock); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -4946,7 +4946,7 @@ } // Installs the root blocks and does a local abort. - localService.installRootBlocksFromQuorum(tmp); + localService.installRootBlocks(tmp); } else { @@ -4970,13 +4970,19 @@ } /** - * Verify that the root blocks are consistent with the assumptions for this - * Journal. - * <p> - * Note: When the quorum meets for the first time, we need to take the root + * Install identical root blocks on the journal. This is used for a few + * different conditions in HA. + * <ol> + * <li>When the quorum meets for the first time, we need to take the root * block from the leader and use it to replace both of our root blocks (the * initial root blocks are identical). That will make the root blocks the - * same on all quorum members. + * same on all quorum members.</li> + * <li>REBUILD: When a service goes through an automated disaster recovery, + * we need to install new root blocks in order to make the local journal + * logically empty. This prevents the service from attempting to interpret + * the data on the backing file if there is a restart part way through the + * rebuild operation.</li> + * </ol> * * FIXME We should also verify the following: * @@ -4985,17 +4991,17 @@ * capacity (so there will be room for the write cache * data in the buffers on all nodes). * </pre> + * + * @see QuorumService#installRootBlocks(IRootBlockView) */ - protected void installRootBlocksFromQuorum( - final QuorumService<HAGlue> localService, - final IRootBlockView rootBlock) { + protected void installRootBlocks(final IRootBlockView rootBlock) { - if (_rootBlock.getCommitCounter() != 0) { +// if (_rootBlock.getCommitCounter() != 0) { +// +// throw new IllegalStateException(); +// +// } - throw new IllegalStateException(); - - } - final IRootBlockView rootBlock0 = rootBlock; final IRootBlockView rootBlock1 = new RootBlockView( @@ -5013,7 +5019,6 @@ } } - log.info("Synchronizing root blocks with quorum."); // write root block through to disk and sync. _bufferStrategy.writeRootBlock(rootBlock0, ForceEnum.Force); @@ -5024,8 +5029,7 @@ // Choose the "current" root block. _rootBlock = RootBlockUtility.chooseRootBlock(rootBlock0, rootBlock1); - log.info("Synchronized root blocks with qourum: rootBlock=" - + _rootBlock); + log.warn("Installed new root blocks: rootBlock=" + _rootBlock); /* * We need to reset the backing store with the token for the new quorum. @@ -5829,7 +5833,7 @@ * This is implemented by HAJournal. */ @Override - public Future<Void> sendHAStore(IHARebuildRequest msg) + public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/FileMetadata.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/FileMetadata.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -47,7 +47,6 @@ import com.bigdata.quorum.Quorum; import com.bigdata.rawstore.Bytes; import com.bigdata.rawstore.WormAddressManager; -import com.bigdata.util.ChecksumUtility; /** * Helper object used when opening or creating journal file in any of the @@ -230,17 +229,17 @@ // */ // final private ChecksumUtility checker = new ChecksumUtility(); - /** - * The 1st root block. - */ - protected IRootBlockView rootBlock0; +// /** +// * The 1st root block. +// */ +// protected IRootBlockView rootBlock0; +// +// /** +// * The 2nd root block. +// */ +// protected IRootBlockView rootBlock1; /** - * The 2nd root block. - */ - protected 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. */ @@ -692,13 +691,19 @@ } - /* - * The offset at which the first record will be written. This is - * zero(0) since the buffer offset (0) is the first byte after - * the root blocks. - */ - nextOffset = 0; + /* + * Create the root block objects (in memory). + */ + final RootBlockUtility rbu = new RootBlockUtility(bufferMode, + offsetBits, createTime, quorumToken, UUID.randomUUID()); +// /* +// * The offset at which the first record will be written. This is +// * zero(0) since the buffer offset (0) is the first byte after +// * the root blocks. +// */ +// nextOffset = 0; // Note: Move after we write the RBs. + magic = MAGIC; version = VERSION1; @@ -721,43 +726,49 @@ } - /* - * Generate the root blocks. They are for all practical purposes - * identical (in fact, their timestamps will be distinct). The - * root block are then written into their locations in the file. - */ + /* + * The root block are then written into their locations in the file. + */ { - final ChecksumUtility checker = ChecksumUtility.threadChk.get(); +// final ChecksumUtility checker = ChecksumUtility.threadChk.get(); +// +// // use the caller's value for offsetBits. +// this.offsetBits = offsetBits; +// final long commitCounter = 0L; +// final long firstCommitTime = 0L; +// final long lastCommitTime = 0L; +// final long commitRecordAddr = 0L; +// final long commitRecordIndexAddr = 0L; +// final UUID uuid = UUID.randomUUID(); // journal's UUID. +// final StoreTypeEnum stenum = bufferMode.getStoreType(); +// if (createTime == 0L) { +// throw new IllegalArgumentException( +// "Create time may not be zero."); +// } +// this.createTime = createTime; +// this.closeTime = 0L; +// final long blockSequence = IRootBlockView.NO_BLOCK_SEQUENCE; +// final IRootBlockView rootBlock0 = new RootBlockView(true, +// offsetBits, nextOffset, firstCommitTime, +// lastCommitTime, commitCounter, commitRecordAddr, +// commitRecordIndexAddr, uuid, // +// blockSequence, quorumToken,// +// 0L, 0L, stenum, createTime, closeTime, RootBlockView.currentVersion, checker); +// final IRootBlockView rootBlock1 = new RootBlockView(false, +// offsetBits, nextOffset, firstCommitTime, +// lastCommitTime, commitCounter, commitRecordAddr, +// commitRecordIndexAddr, uuid, // +// blockSequence, quorumToken,// +// 0L, 0L, stenum, createTime, closeTime, RootBlockView.currentVersion, checker); - // use the caller's value for offsetBits. - this.offsetBits = offsetBits; - final long commitCounter = 0L; - final long firstCommitTime = 0L; - final long lastCommitTime = 0L; - final long commitRecordAddr = 0L; - final long commitRecordIndexAddr = 0L; - final UUID uuid = UUID.randomUUID(); // journal's UUID. - final StoreTypeEnum stenum = bufferMode.getStoreType(); - if (createTime == 0L) { - throw new IllegalArgumentException( - "Create time may not be zero."); - } - this.createTime = createTime; - this.closeTime = 0L; - final long blockSequence = IRootBlockView.NO_BLOCK_SEQUENCE; - final IRootBlockView rootBlock0 = new RootBlockView(true, - offsetBits, nextOffset, firstCommitTime, - lastCommitTime, commitCounter, commitRecordAddr, - commitRecordIndexAddr, uuid, // - blockSequence, quorumToken,// - 0L, 0L, stenum, createTime, closeTime, RootBlockView.currentVersion, checker); - final IRootBlockView rootBlock1 = new RootBlockView(false, - offsetBits, nextOffset, firstCommitTime, - lastCommitTime, commitCounter, commitRecordAddr, - commitRecordIndexAddr, uuid, // - blockSequence, quorumToken,// - 0L, 0L, stenum, createTime, closeTime, RootBlockView.currentVersion, checker); + // take various values from the current RB. + this.nextOffset = rbu.rootBlock.getNextOffset(); + this.offsetBits = rbu.rootBlock.getOffsetBits(); + this.createTime = rbu.rootBlock.getCreateTime(); + this.closeTime = rbu.rootBlock.getCloseTime(); + final IRootBlockView rootBlock0 = rbu.rootBlock0; + final IRootBlockView rootBlock1 = rbu.rootBlock1; if (!temporary) { @@ -986,8 +997,8 @@ */ final RootBlockUtility tmp = new RootBlockUtility(opener, file, validateChecksum, alternateRootBlock, ignoreBadRootBlock); - this.rootBlock0 = tmp.rootBlock0; - this.rootBlock1 = tmp.rootBlock1; +// this.rootBlock0 = tmp.rootBlock0; +// this.rootBlock1 = tmp.rootBlock1; this.rootBlock = tmp.rootBlock; // { // Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockUtility.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -32,6 +32,7 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.util.UUID; import org.apache.log4j.Logger; @@ -301,6 +302,72 @@ } /** + * Generate the root blocks. They are for all practical purposes identical. + * + * @param bufferMode + * @param offsetBits + * @param createTime + * @param quorumToken + * @param storeUUID + */ + public RootBlockUtility( + final BufferMode bufferMode, + final int offsetBits, + final long createTime, + final long quorumToken, + final UUID storeUUID + ) { + + if (bufferMode == null) + throw new IllegalArgumentException("BufferMode is required."); + + if (createTime == 0L) + throw new IllegalArgumentException("Create time may not be zero."); + + if (storeUUID == null) + throw new IllegalArgumentException("Store UUID is required."); + + final ChecksumUtility checker = ChecksumUtility.threadChk.get(); + + /* + * WORM: The offset at which the first record will be written. This is + * zero(0) since the buffer offset (0) is the first byte after the root + * blocks. + * + * RWStore: The field is ignored. The RWStore skips over a block to have + * a good byte alignment on the file. + */ + final long nextOffset = 0L; + final long closeTime = 0L; + final long commitCounter = 0L; + final long firstCommitTime = 0L; + final long lastCommitTime = 0L; + final long commitRecordAddr = 0L; + final long commitRecordIndexAddr = 0L; + + final StoreTypeEnum stenum = bufferMode.getStoreType(); + + final long blockSequence = IRootBlockView.NO_BLOCK_SEQUENCE; + + rootBlock0 = new RootBlockView(true, + offsetBits, nextOffset, firstCommitTime, + lastCommitTime, commitCounter, commitRecordAddr, + commitRecordIndexAddr, storeUUID, // + blockSequence, quorumToken,// + 0L, 0L, stenum, createTime, closeTime, RootBlockView.currentVersion, checker); + + rootBlock1 = new RootBlockView(false, + offsetBits, nextOffset, firstCommitTime, + lastCommitTime, commitCounter, commitRecordAddr, + commitRecordIndexAddr, storeUUID, // + blockSequence, quorumToken,// + 0L, 0L, stenum, createTime, closeTime, RootBlockView.currentVersion, checker); + + this.rootBlock = rootBlock0; + + } + + /** * Dumps the root blocks for the specified file. * * @param args Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -57,6 +57,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHARootBlockResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -259,7 +260,7 @@ } @Override - public Future<Void> sendHAStore(IHARebuildRequest msg) + public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -466,7 +466,7 @@ } @Override - public void installRootBlocksFromQuorum(IRootBlockView rootBlock) { + public void installRootBlocks(IRootBlockView rootBlock) { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -60,6 +60,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHARootBlockResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -1309,8 +1310,8 @@ } @Override - public Future<Void> sendHAStore(IHARebuildRequest msg) - throws IOException { + public Future<IHARootBlockResponse> sendHAStore( + IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -65,6 +65,7 @@ import com.bigdata.ha.msg.HADigestResponse; import com.bigdata.ha.msg.HALogDigestResponse; import com.bigdata.ha.msg.HALogRootBlocksResponse; +import com.bigdata.ha.msg.HARootBlockResponse; import com.bigdata.ha.msg.IHADigestRequest; import com.bigdata.ha.msg.IHADigestResponse; import com.bigdata.ha.msg.IHAGlobalWriteLockRequest; @@ -74,6 +75,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHARootBlockResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.io.DirectBufferPool; @@ -520,12 +522,10 @@ * Extended to expose this method to the {@link HAQuorumService}. */ @Override - protected void installRootBlocksFromQuorum( - final QuorumService<HAGlue> localService, - final IRootBlockView rootBlock) { + protected void installRootBlocks(final IRootBlockView rootBlock) { - super.installRootBlocksFromQuorum(localService, rootBlock); - + super.installRootBlocks(rootBlock); + } /** @@ -744,14 +744,14 @@ * buffers on a 1MB boundary which will provide more efficient IOs. */ @Override - public Future<Void> sendHAStore(final IHARebuildRequest req) - throws IOException { + public Future<IHARootBlockResponse> sendHAStore( + final IHARebuildRequest req) throws IOException { if (haLog.isDebugEnabled()) haLog.debug("req=" + req); // Task sends an HALog file along the pipeline. - final FutureTask<Void> ft = new FutureTaskMon<Void>( + final FutureTask<IHARootBlockResponse> ft = new FutureTaskMon<IHARootBlockResponse>( new SendStoreTask(req)); // Run task. @@ -765,7 +765,7 @@ /** * Class sends the backing file along the write pipeline. */ - private class SendStoreTask implements Callable<Void> { + private class SendStoreTask implements Callable<IHARootBlockResponse> { private final IHARebuildRequest req; @@ -778,7 +778,7 @@ } - public Void call() throws Exception { + public IHARootBlockResponse call() throws Exception { // The quorum token (must remain valid through this operation). final long quorumToken = getQuorumToken(); @@ -861,8 +861,12 @@ haLog.info("Sent store file: #blocks=" + sequence + ", #bytes=" + (fileExtent - headerSize)); + // The current root block. + final IHARootBlockResponse resp = new HARootBlockResponse( + getRootBlockView()); + // Done. - return null; + return resp; } finally { Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -55,6 +55,7 @@ import com.bigdata.ha.msg.HAWriteSetStateRequest; import com.bigdata.ha.msg.IHALogRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; +import com.bigdata.ha.msg.IHARootBlockResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateResponse; @@ -65,6 +66,7 @@ import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.IHABufferStrategy; import com.bigdata.journal.IRootBlockView; +import com.bigdata.journal.RootBlockUtility; import com.bigdata.quorum.Quorum; import com.bigdata.quorum.QuorumEvent; import com.bigdata.quorum.QuorumException; @@ -507,8 +509,8 @@ if (quorumService != null) { /* - * FIXME What if we are already running a ShutdownTask? We should - * just submit a ShutdownTask here and let it work this out. + * FIXME SHUTDOWN: What if we are already running a ShutdownTask? We + * should just submit a ShutdownTask here and let it work this out. */ /* @@ -548,13 +550,13 @@ * Terminate the watchers and threads that are monitoring and * maintaining our reflection of the global quorum state. * - * FIXME This can deadlock if there is a concurrent attempt to - * addMember(), addPipeline(), castVote(), serviceJoin(), etc. - * The deadlock arises because we are undoing all of those - * things in this thread and then waiting until the Condition is - * satisified. With a concurrent action to do the opposite - * thing, we can wind up with the end state that we are not - * expecting and just waiting forever inside of + * FIXME SHUTDOWN: This can deadlock if there is a concurrent + * attempt to addMember(), addPipeline(), castVote(), + * serviceJoin(), etc. The deadlock arises because we are + * undoing all of those things in this thread and then waiting + * until the Condition is satisified. With a concurrent action + * to do the opposite thing, we can wind up with the end state + * that we are not expecting and just waiting forever inside of * AbstractQuorum.doConditionXXXX() for our condition variable * to reach the desired state. * @@ -1353,55 +1355,7 @@ } // call() } // class RunMetTask - -// @Override -// public void pipelineAdd() { -// -// super.pipelineAdd(); -// -// final Quorum<?, ?> quorum = getQuorum(); -// -// final long token = quorum.token(); -// -// conditionalStartResync(token); -// -// } -// /** -// * Conditionally start resynchronization of this service with the met -// * quorum. -// * -// * @param token -// */ -// private void conditionalStartResync(final long token) { -// -// if (isPipelineMember() && !isJoinedMember(token) -// && getQuorum().isQuorumMet() -// && (resyncFutureRef.get() == null || runStateRef.get() != RunStateEnum.Resync)) { -// -//// && (resyncFuture == null || runStateRef.get() == RunStateEnum.Resync)) { -// -// /* -// * Start the resynchronization protocol. -// */ -// -// enterRunState(new ResyncTask()); -// -//// if (resyncFuture != null) { -//// -//// // Cancel future if already running (paranoia). -//// resyncFuture.cancel(true/* mayInterruptIfRunning */); -//// -//// } -//// -//// resyncFuture = new MonitoredFutureTask<Void>(new ResyncTask()); -//// -//// journal.getExecutorService().submit(resyncFuture); -// -// } -// -// } - /** * Rebuild the backing store from scratch. * <p> @@ -1447,68 +1401,67 @@ */ private class RebuildTask extends RunStateCallable<Void> { + /** + * The quorum token in effect when we began the rebuild. + */ private final long token; + + /** + * The quorum leader. This is fixed until the quorum breaks. + */ private final S leader; - public RebuildTask() { + public RebuildTask(final long token) { super(RunStateEnum.Rebuild); // run while quorum is met. - token = getQuorum().token(); + this.token = token; // The leader for that met quorum (RMI interface). leader = getLeader(token); } -// @Override -// public Void doCall() throws Exception { -// -// -//// final long readLock = leader.newTx(ITx.READ_COMMITTED); -// -// try { -// -//// doRun(readLock); -// doRun(); -// -// } catch (Throwable t) { -// -// if (InnerCause.isInnerCause(t, InterruptedException.class)) { -// -// log.info("Interrupted."); -// -// } -// -// log.error(t, t); -// -// } finally { -// -//// // release the read lock. -//// leader.abort(readLock); -// -// } -// -// return null; -// -// } - - protected Void doRun(/*final long readLock*/) throws Exception { + protected Void doRun() throws Exception { - if (true) - throw new UnsupportedOperationException(); - -// haLog.warn("REBUILD: " + server.getServiceName()); + /* + * DO NOT start a rebuild if the quorum is broken. Instead, we + * will try again after SeekConsensus. + */ + getQuorum().assertQuorum(token); /* - * Note: We need to discard any writes that might have been - * buffered before we start the resynchronization of the local - * store. + * Rebuild needs to throw away anything that is buffered on the + * local backing file to prevent any attempts to interpret the + * data on the backing file in light of its current root blocks. + * To do this, we overwrite the root blocks. */ + { - journal.doLocalAbort(); + // The current root block. + final IRootBlockView rb = journal.getRootBlockView(); + // Use timestamp from leader (not critical). + final long createTime = leader.nextTimestamp(); + + // New root blocks for a (logically) empty Journal. + final RootBlockUtility rbu = new RootBlockUtility(journal + .getBufferStrategy().getBufferMode(), + rb.getOffsetBits(), createTime, token, rb.getUUID()); + + /* + * Install both root blocks. + * + * Note: This will take us through a local abort. That is + * important. We need to discard any writes that might have + * been buffered before we start the resynchronization of + * the local store. + */ + installRootBlocks(rbu.rootBlock); + + } + /* * Make a note of the root block that is in effect when we being * the rebuild procedure. Once we have replicated the backing @@ -1517,7 +1470,7 @@ * catch up, we can atomically join and lay down the root blocks * from the leader for the most recent commit point. */ - final IRootBlockView rootBlockAtStartOfRebuild = leader + final IRootBlockView rootBlockAtStartOfCopy = leader .getRootBlock( new HARootBlockRequest(null/* storeUUID */)) .getRootBlock(); @@ -1533,13 +1486,15 @@ * Note: This remoteFuture MUST be cancelled if the RebuildTask * is interrupted. */ - final Future<Void> remoteFuture = leader + final Future<IHARootBlockResponse> remoteFuture = leader .sendHAStore(new HARebuildRequest(getServiceId())); + final IRootBlockView rootBlockAtEndOfCopy; + try { // Wait for the raw store to be replicated. - remoteFuture.get(); + rootBlockAtEndOfCopy = remoteFuture.get().getRootBlock(); } finally { @@ -1549,31 +1504,45 @@ } /* - * FIXME REBUILD: Apply all HALogs (request each log starting - * with the commit point identified above, and apply as - * received, but DO NOT lay down root blocks or go through - * commit points). [Refactor this code from the RESYNC task.] + * Figure out the commit point that the leader was in when the + * copy operation finished. We can not lay down root blocks + * until we have caught up to this commit point. + */ + final long commitPointAtEndOfCopy = rootBlockAtEndOfCopy + .getCommitCounter(); + + /* + * Request each HALog starting with the commit point identified + * above. As each HALog is received, we write it onto a local + * HALog file and apply the write cache blocks to the backing + * store. However, we do NOT lay down root blocks or go through + * commit points until we have caught up on all writes since the + * commitCounter at which we started to replicate the leader's + * backing store. * - * Note: The quorum WILL be maintaining HALog files since (a) - * they are maintained for every active write set; and (b) the - * quorum is not fully met since this service is not joined with - * the met quorum. + * Note: All services joined with the met quorum WILL be + * maintaining HALog files since (a) they are maintained for + * every active write set; and (b) the quorum is not fully met + * since this service is not joined with the met quorum. */ { - + // The last commit point that has been captured. - long commitCounter = rootBlockAtStartOfRebuild + long commitCounter = rootBlockAtStartOfCopy .getCommitCounter(); // Until joined with the met quorum. while (!getQuorum().getMember().isJoinedMember(token)) { - // Abort if the quorum breaks. - getQuorum().assertQuorum(token); + /* + * Note: We do NOT go through local commits with each + * replicated write set until we are caught up. + */ + final boolean incremental = commitCounter >= commitPointAtEndOfCopy; // Replicate and apply the next write set replicateAndApplyWriteSet(leader, token, - commitCounter + 1, false/* incremental */); + commitCounter + 1, incremental); // Replicate the next write set. commitCounter++; @@ -1617,8 +1586,7 @@ private final long token; /** - * The quorum leader. This is fixed until the quorum breaks or the - * resync ends. + * The quorum leader. This is fixed until the quorum breaks. */ private final S leader; @@ -1665,25 +1633,29 @@ journal.doLocalAbort(); + /* + * We will do a local commit with each HALog (aka write set) + * that is replicated. This let's us catch up incrementally with + * the quorum. + */ + final boolean incremental = true; + // Until joined with the met quorum. while (!getQuorum().getMember().isJoinedMember(token)) { - // Abort if the quorum breaks. - getQuorum().assertQuorum(token); - // The current commit point on the local store. final long commitCounter = journal.getRootBlockView() .getCommitCounter(); // Replicate and apply the next write set replicateAndApplyWriteSet(leader, token, commitCounter + 1, - true/* incremental */); + incremental); } // Done return null; - + } } // class ResyncTask @@ -1696,7 +1668,7 @@ * * @param leader * The quorum leader. - * @param quorumToken + * @param token * The quorum token that must remain valid throughout this * operation. * @param closingCommitCounter @@ -1716,11 +1688,19 @@ * @throws InterruptedException */ private void replicateAndApplyWriteSet(final S leader, - final long quorumToken, final long closingCommitCounter, + final long token, final long closingCommitCounter, final boolean incremental) throws FileNotFoundException, - IOException, - InterruptedException, ExecutionException { + IOException, InterruptedException, ExecutionException { + if (leader == null) + throw new IllegalArgumentException(); + + if (closingCommitCounter <= 0) + throw new IllegalArgumentException(); + + // Abort if the quorum breaks. + getQuorum().assertQuorum(token); + if (haLog.isInfoEnabled()) haLog.info("RESYNC: commitCounter=" + closingCommitCounter + ", incremental=" + incremental); @@ -1738,49 +1718,33 @@ /* * Oops. The leader does not have that log file. * - * We will have to rebuild the service from scratch since we - * do not have the necessary HA Log files to synchronize - * with the existing quorum. + * We will have to rebuild the service from scratch since we do + * not have the necessary HA Log files to synchronize with the + * existing quorum. * - * TODO RESYNC : It is possible to go to another service in - * the met quorum for the same log file, but it needs to be - * a service that is UPSTREAM of this service. + * Note: If we are already doing a REBUILD (incremental=false), + * then we will restart the REBUILD. Rationale: if someone + * restarts the service after the shutdown, it is going to do + * another REBUILD anyway. Likely causes for the missing HALog + * on the leader are file system errors or someone deleting the + * HALog files that we need. However, REBUILD is still + * semantically correct so long as we restart the procedure. + * + * TODO RESYNC : It is possible to go to another service in the + * met quorum for the same log file, but it needs to be a + * service that is UPSTREAM of this service. */ - final String msg = "HA Log not available: commitCounter=" + final String msg = "HALog not available: commitCounter=" + closingCommitCounter; - if (incremental) { + log.error(msg); - log.error(msg); + enterRunState(new RebuildTask(token)); - enterRunState(new RebuildTask()); - - // Force immediate exit of the resync protocol. - throw new InterruptedException(msg); - - } else { - - /* - * If we are already doing a rebuild (versus resync) then it - * is a fatal error if we can not locate the necessary HALog - * files. - * - * Note: This could be caused by a bug or if someone deleted - * the necessary HALog file on the leader. Either way, - * manual intervention is required. - */ - - log.fatal(msg); - - // Shutdown. - server.shutdownNow(false/* destroy */); - - // Rethrow the exception. - throw new IOException(ex); - - } - + // Force immediate exit of the resync protocol. + throw new InterruptedException(msg); + } // root block when the quorum started that write set. @@ -1802,14 +1766,13 @@ } /* - * If the local journal is empty, then we need to replace both - * of it's root blocks with the opening root block. + * If the local journal is empty, then we need to replace both of + * it's root blocks with the opening root block. */ - if (journal.getRootBlockView().getCommitCounter() == 0 - && incremental) { + if (closingCommitCounter == 1 && incremental) { // Install the initial root blocks. - installRootBlocksFromQuorum(openRootBlock); + installRootBlocks(openRootBlock); } @@ -1848,7 +1811,7 @@ * effectively read-only). */ - if (conditionalJoinWithMetQuorum(leader, quorumToken, + if (conditionalJoinWithMetQuorum(leader, token, closingCommitCounter - 1, incremental)) { /* @@ -1870,35 +1833,66 @@ * in the write pipeline. Replicating from the leader is simpler * conceptually and makes for simpler code. */ + { + + Future<Void> ft = null; + boolean success = false; + try { - Future<Void> ft = null; - try { + if (haLog.isDebugEnabled()) + haLog.debug("HALOG REPLICATION START: closingCommitCounter=" + + closingCommitCounter + + ", incremental=" + + incremental); + + ft = leader + .sendHALogForWriteSet(new HALogRequest( + server.serviceUUID, closingCommitCounter, + true/* incremental */)); - ft = leader - .sendHALogForWriteSet(new HALogRequest( - server.serviceUUID, closingCommitCounter, true/* incremental */)); + // Wait until all write cache blocks are received. + ft.get(); - /* - * Wait until all write cache blocks are received. - */ - if (log.isDebugEnabled()) - log.debug("WAITING ON SEND HALOG FUTURE"); + success = true; - ft.get(); - - } finally { + } catch(ExecutionException ex) { - if (ft != null) { + final String msg = "HALog not available: commitCounter=" + + closingCommitCounter; - if (log.isDebugEnabled()) - log.debug("HALOG FUTURE: isDone=" + ft.isDone()); + log.error(msg, ex); - ft.cancel(true/* mayInterruptIfRunning */); + /* + * If the quorum broke, then we will re-enter SeekConsensus + * when it meets. + */ + getQuorum().assertQuorum(token); - ft = null; + /* + * Otherwise restart resync/rebuild. + * + * Note: If we can not get the HALog root blocks (at the top + * of this method) then we will enter REBUILD at that top. + */ + enterRunState(incremental ? new ResyncTask(token) + : new RebuildTask(token)); - } + // Force immediate exit of the resync protocol. + throw new InterruptedException(msg); + } finally { + + if (ft != null) { + // ensure terminated. + ft.cancel(true/* mayInterruptIfRunning */); + } + + if (haLog.isDebugEnabled()) + haLog.debug("HALOG REPLICATION DONE : closingCommitCounter=" + + closingCommitCounter + ", success=" + success); + + } + } /* @@ -1949,6 +1943,11 @@ if (incremental) { + /* + * FIXME REBUILD: We need to put down BOTH root blocks if we are + * going to transition from non-incremental to incremental. + */ + // Local commit. journal.doLocalCommit( (QuorumService<HAGlue>) HAQuorumService.this, @@ -1966,8 +1965,8 @@ } if (haLog.isInfoEnabled()) - haLog.info("RESYNC: caught up to commitCounter=" - + closingCommitCounter); + haLog.info("Replicated write set: commitCounter=" + + closingCommitCounter + ", incremental=" + incremental); } @@ -2016,8 +2015,7 @@ + ", openingCommitCounter=" + openingCommitCounter + ", currentWriteSetStateOnLeader=" + currentWriteSetStateOnLeader // - + ", incremental=" - + incremental); + + ", incremental=" + incremental); if (!sameCommitCounter || currentWriteSetStateOnLeader.getSequence() > 0L) { @@ -2130,14 +2128,12 @@ // Verify that the quorum is valid. getQuorum().assertQuorum(quorumToken); - haLog.warn("RESYNC : joined met quorum. commitCounter=" - + openingCommitCounter + ", lastCommitTimeOfLeader=" + haLog.warn("Joined met quorum: runState=" + runStateRef + + ", commitCounter=" + openingCommitCounter + + ", lastCommitTimeOfLeader=" + lastCommitTimeOfQuorumLeader + ", nextBlockSeq=" + logWriter.getSequence()); - // See quorumMeet() -// journal.setQuorumToken(quorumToken); - // Verify that the quorum is valid. getQuorum().assertQuorum(quorumToken); @@ -2193,7 +2189,7 @@ * "non-empty" when the file state is not fully consistent * with the leader. * - * Note: Replicaed backing store write blocks MUST be + * Note: Replicated backing store write blocks MUST be * written directly onto the backing FileChannel after * correcting the offset (which is relative to the root * block). Even for the RWStore, the replicated backing @@ -2682,12 +2678,10 @@ } - @SuppressWarnings("unchecked") @Override - public void installRootBlocksFromQuorum(final IRootBlockView rootBlock) { + public void installRootBlocks(final IRootBlockView rootBlock) { - journal.installRootBlocksFromQuorum((QuorumService<HAGlue>) this, - rootBlock); + journal.installRootBlocks(rootBlock); } @@ -2698,27 +2692,6 @@ } -// /** -// * Conditionally create the default KB instance. -// * -// * @see NSSConfigurationOptions -// * -// * @throws Exception -// */ -// private void conditionalCreateDefaultKB() throws Exception { -// -// final String COMPONENT = NSSConfigurationOptions.COMPONENT; -// -// final String namespace = (String) config.getEntry(COMPONENT, -// NSSConfigurationOptions.NAMESPACE, String.class, -// NSSConfigurationOptions.DEFAULT_NAMESPACE); -// -// final boolean create = (Boolean) config.getEntry(COMPONENT, -// NSSConfigurationOptions.CREATE, Boolean.TYPE, -// NSSConfigurationOptions.DEFAULT_CREATE); -// -// } - /** * Setup and start the {@link NanoSparqlServer}. * <p> Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java 2013-02-18 19:56:37 UTC (rev 6909) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java 2013-02-19 15:34:29 UTC (rev 6910) @@ -17,6 +17,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHARootBlockResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -244,7 +245,7 @@ } @Override - public Future<Void> sendHAStore(IHARebuildRequest msg) + public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-19 17:29:16
|
Revision: 6911 http://bigdata.svn.sourceforge.net/bigdata/?rev=6911&view=rev Author: thompsonbry Date: 2013-02-19 17:29:04 +0000 (Tue, 19 Feb 2013) Log Message: ----------- sendHAStore() now returns both root blocks as of the start of the file copy. The rebuild task was modified to immediately put down those root blocks once the file copy is finished. this is a much better decision pattern for rebuild. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IRootBlockView.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java branches/READ_CACHE/bigdata/src/java/com/bigdata/util/ChecksumUtility.java branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java Added Paths: ----------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HASendStoreResponse.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASendStoreResponse.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -48,6 +48,7 @@ import com.bigdata.ha.msg.IHARebuildRequest; import com.bigdata.ha.msg.IHARootBlockRequest; import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -200,7 +201,7 @@ } @Override - public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + public Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) throws IOException { return delegate.sendHAStore(msg); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAPipelineGlue.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -37,7 +37,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; -import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -211,7 +211,7 @@ * will report the current root block in effect as of the moment * when the <code>sendHAStore</code> operation was completed. */ - Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) throws IOException; // /** Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -92,8 +92,8 @@ long getPrepareTimeout(); /** - * Install identical root blocks on the local service. This is used for a - * few different conditions in HA. + * Install root blocks on the local service. This is used for a few + * different conditions in HA. * <ol> * <li>When the quorum meets for the first time, we need to take the root * block from the leader and use it to replace both of our root blocks (the @@ -110,9 +110,12 @@ * block will be installed as both root block ZERO (0) and root block ONE * (1). * - * @param rootBlock - * The root block. + * @param rootBlock0 + * Root block ZERO (0). + * @param rootBlock1 + * Root block ONE (1). */ - void installRootBlocks(final IRootBlockView rootBlock); + void installRootBlocks(final IRootBlockView rootBlock0, + final IRootBlockView rootBlock1); } Added: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HASendStoreResponse.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HASendStoreResponse.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HASendStoreResponse.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -0,0 +1,103 @@ +/** + +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.ha.msg; + +import java.nio.ByteBuffer; + +import com.bigdata.btree.BytesUtil; +import com.bigdata.journal.IRootBlockView; +import com.bigdata.journal.RootBlockView; +import com.bigdata.util.ChecksumUtility; + +public class HASendStoreResponse implements IHASendStoreResponse { + + /** + * + */ + private static final long serialVersionUID = 1L; + + final private byte[] rootBlock0; + final private byte[] rootBlock1; + final long byteCount; + final long blockCount; + + public HASendStoreResponse(final IRootBlockView rootBlock0, + final IRootBlockView rootBlock1, final long byteCount, + final long blockCount) { + + if (rootBlock0 == null) + throw new IllegalArgumentException(); + + if (rootBlock1 == null) + throw new IllegalArgumentException(); + + this.rootBlock0 = BytesUtil.toArray(rootBlock0.asReadOnlyBuffer()); + + this.rootBlock1 = BytesUtil.toArray(rootBlock1.asReadOnlyBuffer()); + + this.byteCount = byteCount; + + this.blockCount = blockCount; + + } + + @Override + public IRootBlockView getRootBlock0() { + + return new RootBlockView(true, ByteBuffer.wrap(rootBlock0), + new ChecksumUtility()); + + } + + @Override + public IRootBlockView getRootBlock1() { + + return new RootBlockView(false/* rootBlock0 */, + ByteBuffer.wrap(rootBlock1), new ChecksumUtility()); + + } + + @Override + public long getByteCount() { + + return byteCount; + + } + + @Override + public long getBlockCount() { + + return blockCount; + + } + + public String toString() { + + return getClass() + "{rootBlock0=" + getRootBlock0() + ", rootBlock1=" + + getRootBlock1() + ", bytesSent=" + getByteCount() + + ", blocksSent=" + getBlockCount() + "}"; + + } + +} Added: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASendStoreResponse.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASendStoreResponse.java (rev 0) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASendStoreResponse.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -0,0 +1,62 @@ +/** + +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.ha.msg; + +import com.bigdata.journal.IRootBlockView; + +/** + * Interface for a response for a request to send the backing file in + * support of a disaster rebuild. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public interface IHASendStoreResponse extends IHAMessage { + + /** + * Root block ZERO (0) for the service whose backing store was sent + * down the write pipeline in response to the request. + * + * @return The root block and never <code>null</code>. + */ + IRootBlockView getRootBlock0(); + + /** + * Root block ONE (1) for the service whose backing store was sent + * down the write pipeline in response to the request. + * + * @return The root block and never <code>null</code>. + */ + IRootBlockView getRootBlock1(); + + /** + * The #of bytes that were sent in fulfillment of the request. + */ + long getByteCount(); + + /** + * The #of write cache blocks that were sent in fulfillment of the request. + */ + long getBlockCount(); + +} Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -116,6 +116,7 @@ import com.bigdata.ha.msg.IHARebuildRequest; import com.bigdata.ha.msg.IHARootBlockRequest; import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -4946,7 +4947,9 @@ } // Installs the root blocks and does a local abort. - localService.installRootBlocks(tmp); + localService.installRootBlocks( + tmp.asRootBlock(true/* rootBlock0 */), + tmp.asRootBlock(false/* rootBlock0 */)); } else { @@ -4994,19 +4997,29 @@ * * @see QuorumService#installRootBlocks(IRootBlockView) */ - protected void installRootBlocks(final IRootBlockView rootBlock) { + protected void installRootBlocks(final IRootBlockView rootBlock0, + final IRootBlockView rootBlock1) { + if (rootBlock0 == null) + throw new IllegalArgumentException(); + if (rootBlock1 == null) + throw new IllegalArgumentException(); + if (!rootBlock0.isRootBlock0()) + throw new IllegalArgumentException(); + if (rootBlock1.isRootBlock0()) + throw new IllegalArgumentException(); + // if (_rootBlock.getCommitCounter() != 0) { // // throw new IllegalStateException(); // // } - final IRootBlockView rootBlock0 = rootBlock; +// final IRootBlockView rootBlock0 = rootBlock; +// +// final IRootBlockView rootBlock1 = new RootBlockView( +// false/* rootBlock0 */, rootBlock0.asReadOnlyBuffer(), checker); - final IRootBlockView rootBlock1 = new RootBlockView( - false/* rootBlock0 */, rootBlock0.asReadOnlyBuffer(), checker); - // Check the root blocks before we install them. { if (!_rootBlock.getStoreType().equals(rootBlock0.getStoreType())) { @@ -5029,7 +5042,8 @@ // Choose the "current" root block. _rootBlock = RootBlockUtility.chooseRootBlock(rootBlock0, rootBlock1); - log.warn("Installed new root blocks: rootBlock=" + _rootBlock); + haLog.warn("Installed new root blocks: rootBlock0=" + rootBlock0 + + ", rootBlock1=" + rootBlock1); /* * We need to reset the backing store with the token for the new quorum. @@ -5833,7 +5847,7 @@ * This is implemented by HAJournal. */ @Override - public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + public Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } @@ -5905,6 +5919,40 @@ } + /** + * Return both root blocks (atomically). + * <p> + * Note: This takes a lock to ensure that the root blocks are consistent + * with a commit point on the backing store. + */ + protected IRootBlockView[] getRootBlocks() { + + final Lock lock = _fieldReadWriteLock.readLock(); + + lock.lock(); + + try { + + final ChecksumUtility checker = ChecksumUtility.getCHK(); + + final IRootBlockView rb0 = new RootBlockView( + true/* rootBlock0 */, getBufferStrategy() + .readRootBlock(true/* rootBlock0 */), checker); + + final IRootBlockView rb1 = new RootBlockView( + false/* rootBlock0 */, getBufferStrategy() + .readRootBlock(false/* rootBlock0 */), checker); + + return new IRootBlockView[] { rb0, rb1 }; + + } finally { + + lock.unlock(); + + } + + } + @Override public Future<Void> bounceZookeeperConnection() { final FutureTask<Void> ft = new FutureTaskMon<Void>(new Runnable() { Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IRootBlockView.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IRootBlockView.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/IRootBlockView.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -295,4 +295,18 @@ */ public ByteBuffer asReadOnlyBuffer(); + /** + * Return a version of the caller's root block that is flagged as either + * rootBlock0 or rootBlock1 as indicated by the argument. Root blocks are + * immutable, so this will either return your argument or return a new + * {@link IRootBlockView} in which the sense of the {@link #isRootBlock0()} + * flag is now correct. + * + * @param rootBlock0 + * Whether you want rootBlock0 or rootBlock1. + * + * @return The root block. + */ + public IRootBlockView asRootBlock(final boolean rootBlock0); + } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -612,6 +612,22 @@ } + public IRootBlockView asRootBlock(final boolean rootBlock0) { + + if (rootBlock0 && isRootBlock0()) { + + return this; + + } else if (!rootBlock0 && !isRootBlock0()) { + + return this; + + } + + return new RootBlockView(rootBlock0, asReadOnlyBuffer(), checker); + + } + /** * Create a new read-only view from the supplied buffer. * Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/util/ChecksumUtility.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/util/ChecksumUtility.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/util/ChecksumUtility.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -61,18 +61,17 @@ * static access to a ThreadLocal Checksum utility * * @return the ChecksumUtility - * - * @deprecated Use {@link #threadChk} and {@link ThreadLocal#get()}. */ public static ChecksumUtility getCHK() { - ChecksumUtility chk = (ChecksumUtility) threadChk.get(); - - if (chk == null) { - chk = new ChecksumUtility(); - threadChk.set(chk); - } - - return chk; + return threadChk.get(); +// ChecksumUtility chk = (ChecksumUtility) threadChk.get(); +// +// if (chk == null) { +// chk = new ChecksumUtility(); +// threadChk.set(chk); +// } +// +// return chk; } /** Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -57,7 +57,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; -import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -260,7 +260,7 @@ } @Override - public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + public Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -466,7 +466,8 @@ } @Override - public void installRootBlocks(IRootBlockView rootBlock) { + public void installRootBlocks(IRootBlockView rootBlock0, + final IRootBlockView rootBlock1) { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/MockQuorumFixture.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -61,6 +61,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -1310,7 +1311,7 @@ } @Override - public Future<IHARootBlockResponse> sendHAStore( + public Future<IHASendStoreResponse> sendHAStore( IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -65,7 +65,7 @@ import com.bigdata.ha.msg.HADigestResponse; import com.bigdata.ha.msg.HALogDigestResponse; import com.bigdata.ha.msg.HALogRootBlocksResponse; -import com.bigdata.ha.msg.HARootBlockResponse; +import com.bigdata.ha.msg.HASendStoreResponse; import com.bigdata.ha.msg.IHADigestRequest; import com.bigdata.ha.msg.IHADigestResponse; import com.bigdata.ha.msg.IHAGlobalWriteLockRequest; @@ -75,7 +75,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; -import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.io.DirectBufferPool; @@ -522,9 +522,10 @@ * Extended to expose this method to the {@link HAQuorumService}. */ @Override - protected void installRootBlocks(final IRootBlockView rootBlock) { + protected void installRootBlocks(final IRootBlockView rootBlock0, + final IRootBlockView rootBlock1) { - super.installRootBlocks(rootBlock); + super.installRootBlocks(rootBlock0, rootBlock1); } @@ -738,20 +739,20 @@ } /* - * REBUILD: Take a read lock and send everything from the backing - * file, but do not include the root blocks. The first buffer can be - * short (to exclude the root blocks). That will put the rest of the - * buffers on a 1MB boundary which will provide more efficient IOs. + * REBUILD: Take a read lock and send everything from the backing file, + * but do not include the root blocks. The first buffer can be short (to + * exclude the root blocks). That will put the rest of the buffers on a + * 1MB boundary which will provide more efficient IOs. */ @Override - public Future<IHARootBlockResponse> sendHAStore( + public Future<IHASendStoreResponse> sendHAStore( final IHARebuildRequest req) throws IOException { if (haLog.isDebugEnabled()) haLog.debug("req=" + req); // Task sends an HALog file along the pipeline. - final FutureTask<IHARootBlockResponse> ft = new FutureTaskMon<IHARootBlockResponse>( + final FutureTask<IHASendStoreResponse> ft = new FutureTaskMon<IHASendStoreResponse>( new SendStoreTask(req)); // Run task. @@ -765,7 +766,7 @@ /** * Class sends the backing file along the write pipeline. */ - private class SendStoreTask implements Callable<IHARootBlockResponse> { + private class SendStoreTask implements Callable<IHASendStoreResponse> { private final IHARebuildRequest req; @@ -778,13 +779,17 @@ } - public IHARootBlockResponse call() throws Exception { + public IHASendStoreResponse call() throws Exception { // The quorum token (must remain valid through this operation). final long quorumToken = getQuorumToken(); // Grab a read lock. final long txId = newTx(ITx.READ_COMMITTED); + + // Get both root blocks (atomically). + final IRootBlockView[] rootBlocks = getRootBlocks(); + IBufferAccess buf = null; try { @@ -861,10 +866,10 @@ haLog.info("Sent store file: #blocks=" + sequence + ", #bytes=" + (fileExtent - headerSize)); - // The current root block. - final IHARootBlockResponse resp = new HARootBlockResponse( - getRootBlockView()); - + // The root blocks (from above) and stats on the operation. + final IHASendStoreResponse resp = new HASendStoreResponse( + rootBlocks[0], rootBlocks[1], totalBytes, sequence); + // Done. return resp; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -55,7 +55,8 @@ import com.bigdata.ha.msg.HAWriteSetStateRequest; import com.bigdata.ha.msg.IHALogRequest; import com.bigdata.ha.msg.IHALogRootBlocksResponse; -import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateResponse; @@ -738,12 +739,19 @@ if (InnerCause.isInnerCause(t, InterruptedException.class)) { + // Note: This is a normal exit condition. log.info("Interrupted."); - + } else { log.error(t, t); + /* + * Unhandled error. Transition to SeekConsensus! + */ + + enterRunState(new SeekConsensusTask()); + } if (t instanceof Exception) @@ -764,6 +772,21 @@ } + /** + * Core method. + * <p> + * Note: The service will AUTOMATICALLY transition to + * {@link RunStateEnum#SeekConsensus} if there is an abnormal exit + * from this method UNLESS it has entered + * {@link RunStateEnum#Shutdown}. + * + * @return <T> if this is a normal exit. + * + * @throws InterruptedException + * if this is a normal exit. + * @throws Exception + * if this is an abnormal exit. + */ abstract protected T doRun() throws Exception; /** @@ -1442,8 +1465,9 @@ // The current root block. final IRootBlockView rb = journal.getRootBlockView(); - // Use timestamp from leader (not critical). - final long createTime = leader.nextTimestamp(); + // Use timestamp. TODO Why not working w/ TXS? + final long createTime = System.currentTimeMillis(); +// journal.getTransactionService().nextTimestamp(); // New root blocks for a (logically) empty Journal. final RootBlockUtility rbu = new RootBlockUtility(journal @@ -1458,43 +1482,25 @@ * been buffered before we start the resynchronization of * the local store. */ - installRootBlocks(rbu.rootBlock); + installRootBlocks(rbu.rootBlock0, rbu.rootBlock1); } - - /* - * Make a note of the root block that is in effect when we being - * the rebuild procedure. Once we have replicated the backing - * store from the leader, we will need to replay all HALog files - * starting with commitCounter+1 for this root block. Once we - * catch up, we can atomically join and lay down the root blocks - * from the leader for the most recent commit point. - */ - final IRootBlockView rootBlockAtStartOfCopy = leader - .getRootBlock( - new HARootBlockRequest(null/* storeUUID */)) - .getRootBlock(); /* * Replicate the backing store of the leader. * - * Note: We are holding a read lock, so committed allocations - * will not be overwritten. However, the replicated backing file - * will not be logically consistent until we apply all HALog - * files since the commit point noted above. - * * Note: This remoteFuture MUST be cancelled if the RebuildTask * is interrupted. */ - final Future<IHARootBlockResponse> remoteFuture = leader + final Future<IHASendStoreResponse> remoteFuture = leader .sendHAStore(new HARebuildRequest(getServiceId())); - final IRootBlockView rootBlockAtEndOfCopy; + final IHASendStoreResponse resp; try { // Wait for the raw store to be replicated. - rootBlockAtEndOfCopy = remoteFuture.get().getRootBlock(); + resp = remoteFuture.get(); } finally { @@ -1502,55 +1508,13 @@ remoteFuture.cancel(true/* mayInterruptIfRunning */); } - - /* - * Figure out the commit point that the leader was in when the - * copy operation finished. We can not lay down root blocks - * until we have caught up to this commit point. - */ - final long commitPointAtEndOfCopy = rootBlockAtEndOfCopy - .getCommitCounter(); + + // Caught up on the backing store as of that copy. + installRootBlocks(resp.getRootBlock0(), resp.getRootBlock1()); - /* - * Request each HALog starting with the commit point identified - * above. As each HALog is received, we write it onto a local - * HALog file and apply the write cache blocks to the backing - * store. However, we do NOT lay down root blocks or go through - * commit points until we have caught up on all writes since the - * commitCounter at which we started to replicate the leader's - * backing store. - * - * Note: All services joined with the met quorum WILL be - * maintaining HALog files since (a) they are maintained for - * every active write set; and (b) the quorum is not fully met - * since this service is not joined with the met quorum. - */ - { + // Resync. + enterRunState(new ResyncTask(token)); - // The last commit point that has been captured. - long commitCounter = rootBlockAtStartOfCopy - .getCommitCounter(); - - // Until joined with the met quorum. - while (!getQuorum().getMember().isJoinedMember(token)) { - - /* - * Note: We do NOT go through local commits with each - * replicated write set until we are caught up. - */ - final boolean incremental = commitCounter >= commitPointAtEndOfCopy; - - // Replicate and apply the next write set - replicateAndApplyWriteSet(leader, token, - commitCounter + 1, incremental); - - // Replicate the next write set. - commitCounter++; - - } - - } - // Done. return null; @@ -1638,7 +1602,6 @@ * that is replicated. This let's us catch up incrementally with * the quorum. */ - final boolean incremental = true; // Until joined with the met quorum. while (!getQuorum().getMember().isJoinedMember(token)) { @@ -1648,8 +1611,7 @@ .getCommitCounter(); // Replicate and apply the next write set - replicateAndApplyWriteSet(leader, token, commitCounter + 1, - incremental); + replicateAndApplyWriteSet(leader, token, commitCounter + 1); } @@ -1674,13 +1636,6 @@ * @param closingCommitCounter * The commit counter for the <em>closing</em> root block of * the write set to be replicated. - * @param incremental - * When <code>true</code> this is an incremental - * re-synchronization based on replicated HALog files. When - * <code>false</code>, this is a ground up rebuild (disaster - * recovery). For the ground up rebuild we DO NOT go through - * a local commit with each HALog file that we replicate and - * apply. * * @throws IOException * @throws FileNotFoundException @@ -1688,9 +1643,9 @@ * @throws InterruptedException */ private void replicateAndApplyWriteSet(final S leader, - final long token, final long closingCommitCounter, - final boolean incremental) throws FileNotFoundException, - IOException, InterruptedException, ExecutionException { + final long token, final long closingCommitCounter) + throws FileNotFoundException, IOException, + InterruptedException, ExecutionException { if (leader == null) throw new IllegalArgumentException(); @@ -1702,8 +1657,7 @@ getQuorum().assertQuorum(token); if (haLog.isInfoEnabled()) - haLog.info("RESYNC: commitCounter=" + closingCommitCounter - + ", incremental=" + incremental); + haLog.info("RESYNC: commitCounter=" + closingCommitCounter); final IHALogRootBlocksResponse resp; try { @@ -1769,10 +1723,12 @@ * If the local journal is empty, then we need to replace both of * it's root blocks with the opening root block. */ - if (closingCommitCounter == 1 && incremental) { + if (closingCommitCounter == 1) { // Install the initial root blocks. - installRootBlocks(openRootBlock); + installRootBlocks( + openRootBlock.asRootBlock(true/* rootBlock0 */), + openRootBlock.asRootBlock(false/* rootBlock0 */)); } @@ -1812,7 +1768,7 @@ */ if (conditionalJoinWithMetQuorum(leader, token, - closingCommitCounter - 1, incremental)) { + closingCommitCounter - 1)) { /* * We are caught up and have joined the met quorum. @@ -1841,10 +1797,8 @@ if (haLog.isDebugEnabled()) haLog.debug("HALOG REPLICATION START: closingCommitCounter=" - + closingCommitCounter - + ", incremental=" - + incremental); - + + closingCommitCounter); + ft = leader .sendHALogForWriteSet(new HALogRequest( server.serviceUUID, closingCommitCounter, @@ -1855,31 +1809,10 @@ success = true; - } catch(ExecutionException ex) { - - final String msg = "HALog not available: commitCounter=" - + closingCommitCounter; - - log.error(msg, ex); - /* - * If the quorum broke, then we will re-enter SeekConsensus - * when it meets. + * Note: Uncaught exception will result in SeekConsensus. */ - getQuorum().assertQuorum(token); - - /* - * Otherwise restart resync/rebuild. - * - * Note: If we can not get the HALog root blocks (at the top - * of this method) then we will enter REBUILD at that top. - */ - enterRunState(incremental ? new ResyncTask(token) - : new RebuildTask(token)); - - // Force immediate exit of the resync protocol. - throw new InterruptedException(msg); - + } finally { if (ft != null) { @@ -1941,20 +1874,10 @@ } - if (incremental) { + // Local commit. + journal.doLocalCommit((QuorumService<HAGlue>) HAQuorumService.this, + closeRootBlock); - /* - * FIXME REBUILD: We need to put down BOTH root blocks if we are - * going to transition from non-incremental to incremental. - */ - - // Local commit. - journal.doLocalCommit( - (QuorumService<HAGlue>) HAQuorumService.this, - closeRootBlock); - - } - // Close out the current HALog writer. logLock.lock(); try { @@ -1966,7 +1889,7 @@ if (haLog.isInfoEnabled()) haLog.info("Replicated write set: commitCounter=" - + closingCommitCounter + ", incremental=" + incremental); + + closingCommitCounter); } @@ -1983,21 +1906,14 @@ * @param openingCommitCounter * The commit counter for the <em>opening</em> root block of * the write set that is currently being replicated. - * @param incremental - * When <code>true</code> this is an incremental - * re-synchronization based on replicated HALog files. When - * <code>false</code>, this is a ground up rebuild (disaster - * recovery). For the ground up rebuild we DO NOT go through - * a local commit with each HALog file that we replicate and - * apply. * * @return <code>true</code> iff we were able to join the met quorum. + * * @throws InterruptedException */ private boolean conditionalJoinWithMetQuorum(final S leader, - final long quorumToken, final long openingCommitCounter, - final boolean incremental) throws IOException, - InterruptedException { + final long quorumToken, final long openingCommitCounter) + throws IOException, InterruptedException { // // Get the current root block from the quorum leader. // final IRootBlockView currentRootBlockOnLeader = leader @@ -2014,8 +1930,7 @@ haLog.debug("sameCommitCounter=" + sameCommitCounter + ", openingCommitCounter=" + openingCommitCounter + ", currentWriteSetStateOnLeader=" - + currentWriteSetStateOnLeader // - + ", incremental=" + incremental); + + currentWriteSetStateOnLeader); if (!sameCommitCounter || currentWriteSetStateOnLeader.getSequence() > 0L) { @@ -2063,19 +1978,6 @@ return false; } - - if (!incremental) { - - /* - * FIXME REBUILD : When this is a ground up service rebuild, - * we need to lay down both root blocks atomically when we - * are ready to join the met quorum (or perhaps at the next - * commit point after we join the met quorum). - */ - - throw new UnsupportedOperationException(); - - } final HALogWriter logWriter = journal.getHALogWriter(); @@ -2172,7 +2074,8 @@ final long commitCounter = journal.getRootBlockView() .getCommitCounter(); - if (req != null && !req.isIncremental()) { + if (req != null && !req.isIncremental() + && req instanceof IHARebuildRequest) { /* * This message and payload are part of a ground up service @@ -2182,7 +2085,7 @@ * Note: HALog blocks during rebuild are written onto the * appropriate HALog file using the same rules that apply to * resynchronization. We also capture the root blocks for - * those replicate HALog files. However, during a REBUILD, + * those replicated HALog files. However, during a REBUILD, * we DO NOT go through a local commit for the replicated * HALog files until the service is fully synchronized. This * prevents the service from having root blocks that are @@ -2196,13 +2099,14 @@ * store blocks represent a contiguous extent on the file * NOT scattered writes. * - * FIXME REBUILD : Handle replicated HALog write blocks - * - * FIXME REBUILD : Handle replicated backing store write - * blocks. + * REBUILD : Replicated HALog write blocks are handled just + * like resync (see below). */ - throw new UnsupportedOperationException(); + journal.getBufferStrategy().writeRawBuffer( + (HARebuildRequest) req, msg, data); + + return; } @@ -2227,8 +2131,11 @@ } - if (RunStateEnum.Resync.equals(runStateRef.get())) { + final RunStateEnum runState = runStateRef.get(); + if (RunStateEnum.Resync.equals(runState) + || RunStateEnum.Rebuild.equals(runState)) { + /* * If we are resynchronizing, then pass ALL messages (both * live and historical) into handleResyncMessage(). @@ -2355,6 +2262,9 @@ * of the last resync message. We are caught up. We need * to log and apply this live message, cancel the resync * task, and enter RunMet. + * + * FIXME REBUILD: Verify that we have installed the root + * blocks by this point. */ resyncTransitionToMetQuorum(msg, data); @@ -2679,9 +2589,10 @@ } @Override - public void installRootBlocks(final IRootBlockView rootBlock) { + public void installRootBlocks(final IRootBlockView rootBlock0, + final IRootBlockView rootBlock1) { - journal.installRootBlocks(rootBlock); + journal.installRootBlocks(rootBlock0, rootBlock1); } Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java 2013-02-19 15:34:29 UTC (rev 6910) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/MockQuorumMember.java 2013-02-19 17:29:04 UTC (rev 6911) @@ -18,6 +18,7 @@ import com.bigdata.ha.msg.IHALogRootBlocksResponse; import com.bigdata.ha.msg.IHARebuildRequest; import com.bigdata.ha.msg.IHARootBlockResponse; +import com.bigdata.ha.msg.IHASendStoreResponse; import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; @@ -245,7 +246,7 @@ } @Override - public Future<IHARootBlockResponse> sendHAStore(IHARebuildRequest msg) + public Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) throws IOException { throw new UnsupportedOperationException(); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-20 17:18:15
|
Revision: 6914 http://bigdata.svn.sourceforge.net/bigdata/?rev=6914&view=rev Author: thompsonbry Date: 2013-02-20 17:18:04 +0000 (Wed, 20 Feb 2013) Log Message: ----------- - Modified AbstractQuorum.QuorumWatcherBase.clearToken(), disabling the code that was introduced to cause a service to re-cast its lastCommitTime. This is not safe code. A service must sometimes cast the lastCommitTime of the quorum (after a resync). - Identified a race condition when the quorum meets. The write pipeline is setup incrementally as services do pipelineAdd(). The leader observes the QOURUM_MEET even and can immediately begin writing data onto the pipeline. The followers need to block until they have set journal.quorumToken, obtained the leader's root blocks (if they have an empty journal), and opened the HALogWriter so they are able to received and log writes. There is still a problem with error states that can occur due to the pre-conditions in SeekConsensus. It is not always safe to transition to SeekConsensus automatically due to its pre-conditions. We need to examine the error states more closely. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java Added Paths: ----------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-19 18:02:02 UTC (rev 6913) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-20 17:18:04 UTC (rev 6914) @@ -676,7 +676,7 @@ * exist or can not be read. */ public IHALogReader getReader(final long commitCounter) - throws IOException { + throws FileNotFoundException, IOException { final File logFile = new File(m_haLogDir, HALogWriter.getHALogFileName(commitCounter)); @@ -816,15 +816,31 @@ } static class OpenHALogReader implements IHALogReader { - final FileState m_state; - int m_record = 0; - long m_position = headerSize0; // initial position + private final FileState m_state; + private int m_record = 0; + private long m_position = headerSize0; // initial position - OpenHALogReader(FileState state) { + OpenHALogReader(final FileState state) { m_state = state; m_state.m_accessors++; } + @Override + public IRootBlockView getOpeningRootBlock() throws IOException { + + final RootBlockUtility tmp = new RootBlockUtility(m_state.reopener, + m_state.m_haLogFile, true/* validateChecksum */, + false/* alternateRootBlock */, false/* ignoreBadRootBlock */); + + final IRootBlockView closeRootBlock = tmp.chooseRootBlock(); + + final IRootBlockView openRootBlock = tmp.rootBlock0 == closeRootBlock ? tmp.rootBlock1 + : tmp.rootBlock0; + + return openRootBlock; + + } + @Override public IRootBlockView getClosingRootBlock() throws IOException { final RootBlockUtility tmp = new RootBlockUtility(m_state.reopener, Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java 2013-02-19 18:02:02 UTC (rev 6913) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java 2013-02-20 17:18:04 UTC (rev 6914) @@ -54,6 +54,12 @@ boolean isEmpty(); /** + * The {@link IRootBlockView} for the committed state BEFORE the write set + * contained in the HA log file. + */ + IRootBlockView getOpeningRootBlock() throws IOException; + + /** * The {@link IRootBlockView} for the committed state AFTER the write set * contained in the HA log file has been applied. */ Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-02-19 18:02:02 UTC (rev 6913) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-02-20 17:18:04 UTC (rev 6914) @@ -2709,7 +2709,7 @@ final UUID clientId = client.getServiceId(); if (joined.contains(clientId)) { final QuorumMember<S> member = getMember(); - if (member instanceof QuorumService) { + if (false && member instanceof QuorumService) { /* * Set the last commit time. * Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java 2013-02-19 18:02:02 UTC (rev 6913) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java 2013-02-20 17:18:04 UTC (rev 6914) @@ -465,7 +465,7 @@ actor0.memberRemove(); fixture.awaitDeque(); - // wait break to provide visibility for changes (but changes not + // await break to provide visibility for changes (but changes not // required for a quorum break might still not be visible.) quorum0.awaitBreak(); quorum1.awaitBreak(); Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-02-20 17:18:04 UTC (rev 6914) @@ -0,0 +1,1182 @@ +/** + +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.jini.ha; + +import java.io.File; +import java.io.IOException; +import java.net.BindException; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; + +import net.jini.config.Configuration; +import net.jini.config.ConfigurationException; +import net.jini.config.ConfigurationProvider; +import net.jini.core.entry.Entry; +import net.jini.core.lookup.ServiceItem; +import net.jini.core.lookup.ServiceRegistrar; +import net.jini.discovery.LookupDiscoveryManager; +import net.jini.lease.LeaseRenewalManager; +import net.jini.lookup.ServiceDiscoveryManager; + +import org.apache.log4j.Logger; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException.NodeExistsException; +import org.apache.zookeeper.data.ACL; + +import com.bigdata.Banner; +import com.bigdata.ha.HAGlue; +import com.bigdata.ha.HAPipelineGlue; +import com.bigdata.ha.QuorumPipelineImpl; +import com.bigdata.ha.QuorumService; +import com.bigdata.ha.msg.HARebuildRequest; +import com.bigdata.ha.msg.IHALogRequest; +import com.bigdata.ha.msg.IHALogRootBlocksRequest; +import com.bigdata.ha.msg.IHALogRootBlocksResponse; +import com.bigdata.ha.msg.IHARebuildRequest; +import com.bigdata.ha.msg.IHASendStoreResponse; +import com.bigdata.ha.msg.IHASyncRequest; +import com.bigdata.ha.msg.IHAWriteMessage; +import com.bigdata.ha.msg.IHAWriteSetStateRequest; +import com.bigdata.ha.msg.IHAWriteSetStateResponse; +import com.bigdata.jini.start.config.ZookeeperClientConfig; +import com.bigdata.journal.IRootBlockView; +import com.bigdata.quorum.AbstractQuorumMember; +import com.bigdata.quorum.Quorum; +import com.bigdata.quorum.QuorumEvent; +import com.bigdata.quorum.QuorumException; +import com.bigdata.quorum.QuorumListener; +import com.bigdata.quorum.zk.ZKQuorumImpl; +import com.bigdata.service.jini.JiniClient; +import com.bigdata.service.jini.JiniClientConfig; +import com.bigdata.util.concurrent.DaemonThreadFactory; +import com.bigdata.zookeeper.ZooKeeperAccessor; + +/** + * Service for making full and incremental backups. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public class HABackupManager { + + private static final Logger log = Logger.getLogger(HAJournalServer.class); + + /** + * Logger for HA events. + */ + private static final Logger haLog = Logger.getLogger("com.bigdata.haLog"); + + /** + * Configuration options for the {@link HAJournalServer}. + */ + public interface ConfigurationOptions +// extends AbstractServer.ConfigurationOptions + { + + String COMPONENT = HABackupManager.class.getName(); + + /** + * The target replication factor (k). + * + * @see HAJournalServer.ConfigurationOptions#REPLICATION_FACTOR + */ + String REPLICATION_FACTOR = HAJournalServer.ConfigurationOptions.REPLICATION_FACTOR; + + /** + * The {@link InetSocketAddress} at which the {@link HABackupManager} + * receives replicated writes. + * + * @see HAJournalServer.ConfigurationOptions#WRITE_PIPELINE_ADDR + */ + String WRITE_PIPELINE_ADDR = HAJournalServer.ConfigurationOptions.WRITE_PIPELINE_ADDR; + + /** + * The logical service identifier for the {@link HAJournalServer} + * replication cluster that that will be backed up by this service. + * + * @see HAJournalServer.ConfigurationOptions#LOGICAL_SERVICE_ID + */ + String LOGICAL_SERVICE_ID = HAJournalServer.ConfigurationOptions.LOGICAL_SERVICE_ID; + + } + + private LookupDiscoveryManager lookupDiscoveryManager; + + private ServiceDiscoveryManager serviceDiscoveryManager; + + /** + * The {@link Configuration} read based on the args[] provided when the + * server is started. + */ + protected Configuration config; + + /** + * The timeout in milliseconds to await the discovery of a service if there + * is a cache miss (default {@value #DEFAULT_CACHE_MISS_TIMEOUT}). + */ + final protected long cacheMissTimeout; + + /** + * A randomly generated {@link UUID} that this utility uses to identify + * itself. + */ + private final UUID serviceId = UUID.randomUUID(); + + /** + * The directory for the service. This is the directory within which the + * {@link #serviceIdFile} exists. A service MAY have its own concept of a + * data directory, log directory, etc. which can be somewhere else. + */ + private File serviceDir; + + /** + * Caching discovery client for the {@link HAGlue} services. + */ + private HAJournalDiscoveryClient discoveryClient; + + private ZookeeperClientConfig zkClientConfig; + + private ZooKeeperAccessor zka; + + private Quorum<HAGlue, QuorumService<HAGlue>> quorum; + + /** + * The znode name for the logical service. + * + * @see ConfigurationOptions#LOGICAL_SERVICE_ID + */ + private String logicalServiceId; + + /** + * The zpath for the logical service. + * + * @see ConfigurationOptions#LOGICAL_SERVICE_ID + */ + private String logicalServiceZPath; + + /** + * The {@link MyQuorumMember}. + */ + private MyQuorumMember quorumMember; + + /** + * An object used to manage jini service registrar discovery. + */ + public LookupDiscoveryManager getDiscoveryManagement() { + + return lookupDiscoveryManager; + + } + + /** + * An object used to lookup services using the discovered service registars. + */ + public ServiceDiscoveryManager getServiceDiscoveryManager() { + + return serviceDiscoveryManager; + + } + + /** + * Runs {@link AbstractServer#shutdownNow()} and terminates all asynchronous + * processing, including discovery. This is used for the shutdown hook (^C). + * + * @author <a href="mailto:tho...@us...">Bryan + * Thompson</a> + */ + private static class ShutdownThread extends Thread { + + public ShutdownThread() { + + super("shutdownThread"); + + setDaemon(true); + + } + + public void run() { + + /* + * FIXME Interrupt the backup (if any). It is logically empty until + * we write the root blocks. Those need to BOTH be written + * atomically (tricky) -or- just write the same root block twice + * (sneaky). + */ + + } + + } + + private HABackupManager(final String[] args) throws ConfigurationException { + + /* + * The runtime shutdown hook appears to be a robust way to handle ^C by + * providing a clean service termination. + * + * Note: This is setup before we start any async threads, including + * service discovery. + */ + Runtime.getRuntime().addShutdownHook(new ShutdownThread()); + + // Show the copyright banner during startup. + Banner.banner(); + + AbstractServer.setSecurityManager(); + + /* + * Display the banner. + * + * Note: This also installs the UncaughtExceptionHandler. + * + * @see https://sourceforge.net/apps/trac/bigdata/ticket/601 + */ + Banner.banner(); + + /* + * Read jini configuration & service properties + */ + + List<Entry> entries = null; + + final String COMPONENT = getClass().getName(); + final JiniClientConfig jiniClientConfig; + { + + config = ConfigurationProvider.getInstance(args); + + cacheMissTimeout = (Long) config.getEntry(COMPONENT, + AbstractServer.ConfigurationOptions.CACHE_MISS_TIMEOUT, Long.TYPE, + AbstractServer.ConfigurationOptions.DEFAULT_CACHE_MISS_TIMEOUT); + + jiniClientConfig = new JiniClientConfig( + JiniClientConfig.Options.NAMESPACE, config); + + // convert Entry[] to a mutable list. + entries = new LinkedList<Entry>( + Arrays.asList((Entry[]) jiniClientConfig.entries)); + + if (log.isInfoEnabled()) + log.info(jiniClientConfig.toString()); + + } + + /* + * Make sure that the parent directory exists. + * + * Note: the parentDir will be null if the serviceIdFile is in the + * root directory or if it is specified as a filename without any + * parents in the path expression. Note that the file names a file + * in the current working directory in the latter case and the root + * always exists in the former - and in both of those cases we do + * not have to create the parent directory. + */ + serviceDir = (File) config.getEntry(COMPONENT, + AbstractServer.ConfigurationOptions.SERVICE_DIR, File.class); + + if (serviceDir != null && !serviceDir.exists()) { + + log.warn("Creating: " + serviceDir); + + serviceDir.mkdirs(); + + } + + try { + + /* + * Note: This class will perform multicast discovery if ALL_GROUPS + * is specified and otherwise requires you to specify one or more + * unicast locators (URIs of hosts running discovery services). As + * an alternative, you can use LookupDiscovery, which always does + * multicast discovery. + */ + lookupDiscoveryManager = new LookupDiscoveryManager( + jiniClientConfig.groups, jiniClientConfig.locators, + null /* DiscoveryListener */, config); + + /* + * Setup a helper class that will be notified as services join or + * leave the various registrars to which the data server is + * listening. + */ + try { + + serviceDiscoveryManager = new ServiceDiscoveryManager( + lookupDiscoveryManager, new LeaseRenewalManager(), + config); + + } catch (IOException ex) { + + throw new RuntimeException( + "Could not initiate service discovery manager", ex); + + } + + } catch (IOException ex) { + + fatal("Could not setup discovery", ex); + throw new AssertionError();// keep the compiler happy. + + } catch (ConfigurationException ex) { + + fatal("Could not setup discovery", ex); + throw new AssertionError();// keep the compiler happy. + + } + + /* + * Create the service object. + */ + try { + + /* + * Note: By creating the service object here rather than outside of + * the constructor we potentially create problems for subclasses of + * AbstractServer since their own constructor will not have been + * executed yet. + * + * Some of those problems are worked around using a JiniClient to + * handle all aspects of service discovery (how this service locates + * the other services in the federation). + * + * Note: If you explicitly assign values to those clients when the + * fields are declared, e.g., [timestampServiceClient=null] then the + * ctor will overwrite the values set by [newService] since it is + * running before those initializations are performed. This is + * really crufty, may be JVM dependent, and needs to be refactored + * to avoid this subclass ctor init problem. + */ + + if (log.isInfoEnabled()) + log.info("Creating service impl..."); + + // init. +// impl = + newService(config); + +// if (log.isInfoEnabled()) +// log.info("Service impl is " + impl); + + } catch(Exception ex) { + + fatal("Could not start service: "+this, ex); + throw new AssertionError();// keeps compiler happy. + } + + } + + protected void fatal(String msg, Throwable t) { + + log.fatal(msg, t); + + terminate(); + + System.exit(1); + + } + + /** + * Terminates service management threads. + * <p> + * Subclasses which start additional service management threads SHOULD + * extend this method to terminate those threads. The implementation should + * be <strong>synchronized</strong>, should conditionally terminate each + * thread, and should trap, log, and ignore all errors. + */ + private void terminate() { + + if (log.isInfoEnabled()) + log.info("Terminating service management threads."); + +// if (joinManager != null) { +// +// try { +// +// joinManager.terminate(); +// +// } catch (Throwable ex) { +// +// log.error("Could not terminate the join manager: " + this, ex); +// +// } finally { +// +// joinManager = null; +// +// } +// +// } + + if (serviceDiscoveryManager != null) { + + serviceDiscoveryManager.terminate(); + + serviceDiscoveryManager = null; + + } + + if (lookupDiscoveryManager != null) { + + lookupDiscoveryManager.terminate(); + + lookupDiscoveryManager = null; + + } + + } + + protected void newService(final Configuration config) + throws Exception { + + /* + * Verify discovery of at least one ServiceRegistrar. + */ + { + final long begin = System.currentTimeMillis(); + + ServiceRegistrar[] registrars = null; + + long elapsed = 0; + + while ((registrars == null || registrars.length == 0) + && elapsed < TimeUnit.SECONDS.toMillis(10)) { + + registrars = getDiscoveryManagement().getRegistrars(); + + Thread.sleep(100/* ms */); + + elapsed = System.currentTimeMillis() - begin; + + } + + if (registrars == null || registrars.length == 0) { + + throw new RuntimeException( + "Could not discover ServiceRegistrar(s)"); + + } + + if (log.isInfoEnabled()) { + log.info("Found " + registrars.length + " service registrars"); + } + + } + +// // Setup discovery for HAGlue clients. +// final HAJournalDiscoveryClient discoveryClient = new HAJournalDiscoveryClient( +// getServiceDiscoveryManager(), +// null/* serviceDiscoveryListener */, cacheMissTimeout); + + /* + * Setup the Quorum. + */ + + zkClientConfig = new ZookeeperClientConfig(config); + + // znode name for the logical service. + final String logicalServiceId = (String) config.getEntry( + ConfigurationOptions.COMPONENT, + ConfigurationOptions.LOGICAL_SERVICE_ID, String.class); + + final String logicalServiceZPathPrefix = zkClientConfig.zroot + "/" + + HAJournalServer.class.getName(); + + // zpath for the logical service. + final String logicalServiceZPath = logicalServiceZPathPrefix + "/" + + logicalServiceId; + + final int replicationFactor = (Integer) config.getEntry( + ConfigurationOptions.COMPONENT, + ConfigurationOptions.REPLICATION_FACTOR, Integer.TYPE); + + { + + // The address at which this service exposes its write pipeline. + final InetSocketAddress writePipelineAddr = (InetSocketAddress) config + .getEntry(ConfigurationOptions.COMPONENT, + ConfigurationOptions.WRITE_PIPELINE_ADDR, + InetSocketAddress.class); + + /* + * Configuration properties for this HAJournal. + */ + final Properties properties = JiniClient.getProperties( + HAJournal.class.getName(), config); + + // Force the writePipelineAddr into the Properties. + properties.put(HAJournal.Options.WRITE_PIPELINE_ADDR, + writePipelineAddr); + + /* + * Zookeeper quorum. + */ + { + final List<ACL> acl = zkClientConfig.acl; + final String zoohosts = zkClientConfig.servers; + final int sessionTimeout = zkClientConfig.sessionTimeout; + + zka = new ZooKeeperAccessor(zoohosts, sessionTimeout); + + if (!zka.awaitZookeeperConnected(10, TimeUnit.SECONDS)) { + + throw new RuntimeException("Could not connect to zk"); + + } + + if (log.isInfoEnabled()) { + log.info("Connected to zookeeper"); + } + + /* + * Ensure key znodes exist. + */ + try { + zka.getZookeeper() + .create(zkClientConfig.zroot, + new byte[] {/* data */}, acl, + CreateMode.PERSISTENT); + } catch (NodeExistsException ex) { + // ignore. + } + try { + zka.getZookeeper() + .create(logicalServiceZPathPrefix, + new byte[] {/* data */}, acl, + CreateMode.PERSISTENT); + } catch (NodeExistsException ex) { + // ignore. + } + try { + zka.getZookeeper() + .create(logicalServiceZPath, + new byte[] {/* data */}, acl, + CreateMode.PERSISTENT); + } catch (NodeExistsException ex) { + // ignore. + } + + quorum = new ZKQuorumImpl<HAGlue, QuorumService<HAGlue>>( + replicationFactor, zka, acl); + } + +// // The HAJournal. +// this.journal = new HAJournal(properties, quorum); + + } + +// TODO executor for events received in the watcher thread. +// singleThreadExecutor = new LatchedExecutor( +// journal.getExecutorService(), 1/* nparallel */); + +// // our external interface. +// haGlueService = journal.newHAGlue(serviceUUID); +// +// // wrap the external interface, exposing administrative functions. +// final AdministrableHAGlueService administrableService = new AdministrableHAGlueService( +// this, haGlueService); +// +// // return that wrapped interface. +// return administrableService; + + } + + protected void startUp() throws IOException { + + if (log.isInfoEnabled()) + log.info("Starting server."); + + getQuorum().addListener(new QuorumListener() { + + @Override + public void notify(final QuorumEvent e) { + if (log.isTraceEnabled()) + log.trace(e); // TODO LOG @ TRACE + } + }); + + // Setup the quorum client (aka quorum service). + quorumMember = new MyQuorumMember(logicalServiceZPath, serviceId); + + } + + protected void backup() throws Exception { + + final long token = quorumMember.getQuorum().token(); + + quorumMember.getQuorum().assertQuorum(token); + + quorumMember.new BackupTask(token).call(); + + } + + /** + * + * A randomly generated {@link UUID} that this utility uses to identify + * itself. + */ + protected UUID getServiceId() { + return serviceId; + } + + protected Quorum<?,?> getQuorum() { + return quorum; + } + + private class MyQuorumMember extends AbstractQuorumMember<HAPipelineGlue> { + + private final QuorumPipelineImpl<HAPipelineGlue> pipelineImpl = new QuorumPipelineImpl<HAPipelineGlue>(this) { + + @Override + protected void handleReplicatedWrite(final IHASyncRequest req, + final IHAWriteMessage msg, final ByteBuffer data) + throws Exception { + + MyQuorumMember.this.handleReplicatedWrite(req, msg, data); + + } + + @Override + public long getLastCommitTime() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public long getLastCommitCounter() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public void logWriteCacheBlock(IHAWriteMessage msg, ByteBuffer data) + throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public void logRootBlock(IRootBlockView rootBlock) + throws IOException { + // TODO Auto-generated method stub + + } + + @Override + public void purgeHALogs(boolean includeCurrent) { + // TODO Auto-generated method stub + + } + +// @Override +// public long getLastCommitTime() { +// +// return MyQuorumMember.this.getLastCommitTime(); +// +// } +// +// @Override +// public long getLastCommitCounter() { +// +// return MyQuorumMember.this.getLastCommitCounter(); +// +// } +// +// @Override +// public void logWriteCacheBlock(final IHAWriteMessage msg, +// final ByteBuffer data) throws IOException { +// +// MyQuorumMember.this.logWriteCacheBlock(msg, data); +// +// } +// +// @Override +// public void logRootBlock(final IRootBlockView rootBlock) +// throws IOException { +// +// MyQuorumMember.this.logRootBlock(rootBlock); +// +// } +// +// @Override +// public void purgeHALogs(final boolean includeCurrent) { +// +// MyQuorumMember.this.purgeHALogs(includeCurrent); +// +// } + + }; + + /** + * The local implementation of the {@link Remote} interface. + */ + private final HAPipelineGlue service; + +// /** +// * Simple service registrar. +// */ +// private final MockServiceRegistrar<S> registrar; + + /** + * The last lastCommitTime value around which a consensus was achieved + * and initially -1L, but this is cleared to -1L each time the consensus + * is lost. + */ + protected volatile long lastConsensusValue = -1L; + + /** + * The downstream service in the write pipeline. + */ + protected volatile UUID downStreamId = null; + + private volatile ExecutorService executorService = null; + + protected MyQuorumMember(final String logicalServiceId, + final UUID serviceId) throws IOException { + + super(logicalServiceId, serviceId); + + service = new MyQuorumService(); + + /* + * Delegates. + */ + + addListener(this.pipelineImpl); + + } + + @Override + public void start(final Quorum<?, ?> quorum) { + if (executorService == null) + executorService = Executors + .newSingleThreadExecutor(DaemonThreadFactory + .defaultThreadFactory()); + super.start(quorum); + } + + @Override + public void terminate() { + super.terminate(); + if(executorService!=null) { + executorService.shutdownNow(); + executorService = null; + } + } + + public Executor getExecutor() { + return executorService; + } + +// /** +// * Factory for the local service implementation object. +// */ +// abstract S newService(); + + public HAPipelineGlue getService() { + return service; + } + + /** + * Resolve an {@link HAGlue} object from its Service UUID. + */ + @Override + public HAGlue getService(final UUID serviceId) { + +// final HAJournalDiscoveryClient discoveryClient = +// .getDiscoveryClient(); + + final ServiceItem serviceItem = discoveryClient + .getServiceItem(serviceId); + + if (serviceItem == null) { + + // Not found (per the API). + throw new QuorumException("Service not found: uuid=" + + serviceId); + + } + + @SuppressWarnings("unchecked") + final HAGlue service = (HAGlue) serviceItem.service; + + return service; + + } + + /** + * {@inheritDoc} + * + * Overridden to save the <i>lastCommitTime</i> on + * {@link #lastConsensusValue}. + */ + @Override + public void consensus(long lastCommitTime) { + super.consensus(lastCommitTime); + this.lastConsensusValue = lastCommitTime; + } + + @Override + public void lostConsensus() { + super.lostConsensus(); + this.lastConsensusValue = -1L; + } + + /** + * {@inheritDoc} + * + * Overridden to save the current downstream service {@link UUID} on + * {@link #downStreamId} + */ + public void pipelineChange(final UUID oldDownStreamId, + final UUID newDownStreamId) { + super.pipelineChange(oldDownStreamId, newDownStreamId); + this.downStreamId = newDownStreamId; + } + + /** + * {@inheritDoc} + * + * Overridden to clear the {@link #downStreamId}. + */ + public void pipelineRemove() { + super.pipelineRemove(); + this.downStreamId = null; + } + + /** + * @see HAPipelineGlue + */ + protected void handleReplicatedWrite(IHASyncRequest req, + IHAWriteMessage msg, ByteBuffer data) throws Exception { + + // FIXME handle replicated writes! + + } + + /** + * Mock service class. + */ + class MyQuorumService implements HAPipelineGlue { + + private final InetSocketAddress addrSelf; + + public MyQuorumService() throws IOException { + this.addrSelf = new InetSocketAddress(getPort(0)); + } + + public InetSocketAddress getWritePipelineAddr() { + return addrSelf; + } + + /** + * @todo This is not fully general purpose since it is not strictly + * forbidden that the service's lastCommitTime could change, e.g., + * due to explicit intervention, and hence be updated across this + * operation. The real implemention should be a little more + * sophisticated. + */ + public Future<Void> moveToEndOfPipeline() throws IOException { + final FutureTask<Void> ft = new FutureTask<Void>(new Runnable() { + public void run() { + + // note the current vote (if any). + final Long lastCommitTime = getQuorum().getCastVote( + getServiceId()); + + if (isPipelineMember()) { + +// System.err +// .println("Will remove self from the pipeline: " +// + getServiceId()); + + getActor().pipelineRemove(); + +// System.err +// .println("Will add self back into the pipeline: " +// + getServiceId()); + + getActor().pipelineAdd(); + + if (lastCommitTime != null) { + +// System.err +// .println("Will cast our vote again: lastCommitTime=" +// + +lastCommitTime +// + ", " +// + getServiceId()); + + getActor().castVote(lastCommitTime); + + } + + } + } + }, null/* result */); + getExecutor().execute(ft); + return ft; + } + + @Override + public Future<Void> receiveAndReplicate(final IHASyncRequest req, + IHAWriteMessage msg) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public IHALogRootBlocksResponse getHALogRootBlocksForWriteSet( + IHALogRootBlocksRequest msg) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public Future<Void> sendHALogForWriteSet(IHALogRequest msg) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) + throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public IHAWriteSetStateResponse getHAWriteSetState( + IHAWriteSetStateRequest req) { + throw new UnsupportedOperationException(); + } + + } + + /** + * + * Create a full backup. + */ + private class BackupTask implements Callable<Void> { + + /** + * The quorum token in effect when we began the resync. + */ + private final long token; + + /** + * The quorum leader. This is fixed until the quorum breaks. + */ + private final HAGlue leader; + + public BackupTask(final long token) { + + // run while quorum is met. + this.token = token; + + // The leader for that met quorum (RMI interface). + leader = (HAGlue) getLeader(token); + + } + + public Void call() throws Exception { + + /* + * DO NOT start a rebuild if the quorum is broken. Instead, we + * will try again after SeekConsensus. + */ + getQuorum().assertQuorum(token); + + /* + * Replicate the backing store of the leader. + * + * Note: This remoteFuture MUST be cancelled if the RebuildTask + * is interrupted. + * + * FIXME This needs to write onto a configured file. + */ + final Future<IHASendStoreResponse> remoteFuture = leader + .sendHAStore(new HARebuildRequest(getServiceId())); + + final IHASendStoreResponse resp; + + try { + + // Wait for the raw store to be replicated. + resp = remoteFuture.get(); + + } finally { + + // Ensure remoteFuture is cancelled. + remoteFuture.cancel(true/* mayInterruptIfRunning */); + + } + + // Caught up on the backing store as of that copy. + // FIXME Install the root blocks (atomically or as dups of the current root block). +// installRootBlocks(resp.getRootBlock0(), resp.getRootBlock1()); + + // Done + return null; + + } + + } // class BackupTask + + }// class MyQuorumMember + + /** + * Return an open port on current machine. Try the suggested port first. If + * suggestedPort is zero, just select a random port + */ + private static int getPort(final int suggestedPort) throws IOException { + + ServerSocket openSocket; + + try { + + openSocket = new ServerSocket(suggestedPort); + + } catch (BindException ex) { + + // the port is busy, so look for a random open port + openSocket = new ServerSocket(0); + + } + + final int port = openSocket.getLocalPort(); + + openSocket.close(); + + return port; + + } + +// /** +// * Lock controlling access to the {@link #discoveryEvent} {@link Condition}. +// */ +// protected final ReentrantLock discoveryEventLock = new ReentrantLock(); +// +// /** +// * Condition signaled any time there is a {@link DiscoveryEvent} delivered to +// * our {@link DiscoveryListener}. +// */ +// protected final Condition discoveryEvent = discoveryEventLock +// .newCondition(); +// +// /** +// * Signals anyone waiting on {@link #discoveryEvent}. +// */ +// public void discarded(final DiscoveryEvent e) { +// +// try { +// +// discoveryEventLock.lockInterruptibly(); +// +// try { +// +// discoveryEvent.signalAll(); +// +// } finally { +// +// discoveryEventLock.unlock(); +// +// } +// +// } catch (InterruptedException ex) { +// +// return; +// +// } +// +// } +// +// /** +// * Signals anyone waiting on {@link #discoveryEvent}. +// */ +// public void discovered(final DiscoveryEvent e) { +// +// try { +// +// discoveryEventLock.lockInterruptibly(); +// +// try { +// +// discoveryEvent.signalAll(); +// +// } finally { +// +// discoveryEventLock.unlock(); +// +// } +// +// } catch (InterruptedException ex) { +// +// return; +// +// } +// +// } + + /** + * Start the {@link HABackupManager}. + * <p> + * <strong>Jini MUST be running</strong> + * <p> + * <strong>You MUST specify a sufficiently lax security policy</strong>, + * e.g., using <code>-Djava.security.policy=policy.all</code>, where + * <code>policy.all</code> is the name of a policy file. + * + * @param args + * The name of the configuration file. + * + * @throws Exception + */ + public static void main(final String[] args) throws Exception { + + if (args.length == 0) { + + System.err.println("usage: <config-file> [config-overrides]"); + + System.exit(1); + + } + + final HABackupManager server = new HABackupManager(args); + + server.startUp(); + + server.backup(); + + System.exit(0); + + } + +} Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-19 18:02:02 UTC (rev 6913) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-20 17:18:04 UTC (rev 6914) @@ -1,3 +1,26 @@ +/** + +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.jini.ha; import java.io.File; @@ -49,6 +72,7 @@ import com.bigdata.ha.QuorumServiceBase; import com.bigdata.ha.RunState; import com.bigdata.ha.halog.HALogWriter; +import com.bigdata.ha.halog.IHALogReader; import com.bigdata.ha.msg.HALogRequest; import com.bigdata.ha.msg.HALogRootBlocksRequest; import com.bigdata.ha.msg.HARebuildRequest; @@ -61,6 +85,7 @@ import com.bigdata.ha.msg.IHASyncRequest; import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateResponse; +import com.bigdata.io.DirectBufferPool; import com.bigdata.io.IBufferAccess; import com.bigdata.io.writecache.WriteCache; import com.bigdata.jini.start.config.ZookeeperClientConfig; @@ -446,18 +471,9 @@ // Start the quorum. journal.getQuorum().start(quorumService); - // Submit task to seek consensus. - quorumService.enterRunState(quorumService.new SeekConsensusTask()); + // Enter a run state for the HAJournalServer. + quorumService.enterRunState(quorumService.new RestoreTask()); -// /* -// * Note: This CAN NOT moved into QuorumServiceImpl.start(Quorum). I -// * suspect that this is because the quorum watcher would not be running -// * at the moment that we start doing things with the actor, but I have -// * not verified that rationale in depth. -// */ -// doConditionalCastVote(this/* server */, -// (Quorum<HAGlue, QuorumService<HAGlue>>) quorum, journal); - /* * The NSS will start on each service in the quorum. However, * only the leader will create the default KB (if that option is @@ -655,24 +671,19 @@ /** * Enum of the run states. The states are labeled by the goal of the run * state. - * - * @author <a href="mailto:tho...@us...">Bryan - * Thompson</a> */ private enum RunStateEnum { - Start, + Restore, SeekConsensus, RunMet, Resync, - Rebuild, // TODO Not finished. - Backup, // TODO Not implemented. + Rebuild, Shutdown; // TODO We are not using this systematically (no ShutdownTask for this run state). } private final AtomicReference<RunStateEnum> runStateRef = new AtomicReference<RunStateEnum>( null/* none */); - // TODO Could hook this to report out to Jini as well as the haLog file. protected void setRunState(final RunStateEnum runState) { if (runStateRef.get() == RunStateEnum.Shutdown) { @@ -699,24 +710,18 @@ } -// if (haLog.isInfoEnabled()) -// haLog.info("RUNSTATE=" + runState); + haLog.warn("runState=" + runState + ", oldRunState=" + oldRunState + + ", serviceName=" + server.getServiceName()); } private abstract class RunStateCallable<T> implements Callable<T> { - private final RunStateEnum runState; - /** - * Return the {@link RunStateEnum} for this task. + * The {@link RunStateEnum} for this task. */ - public RunStateEnum getRunState() { + protected final RunStateEnum runState; - return runState; - - } - protected RunStateCallable(final RunStateEnum runState) { if (runState == null) @@ -732,8 +737,6 @@ try { - haLog.warn(runState + ": " + server.getServiceName()); - return doRun(); } catch (Throwable t) { @@ -855,9 +858,9 @@ success = true; - if (haLog.isInfoEnabled()) - haLog.info("Entering runState=" - + runStateTask.getClass().getSimpleName()); +// if (haLog.isInfoEnabled()) +// haLog.info("Entering runState=" +// + runStateTask.getClass().getSimpleName()); } finally { @@ -973,6 +976,14 @@ } + @SuppressWarnings("unchecked") + protected void doLocalCommit(final IRootBlockView rootBlock) { + + journal.doLocalCommit((QuorumService<HAGlue>) HAQuorumService.this, + rootBlock); + + } + @Override public void start(final Quorum<?,?> quorum) { @@ -1041,7 +1052,7 @@ return null; } } - + /** * Task to handle a quorum break event. */ @@ -1133,127 +1144,37 @@ // await the quorum meet. final long token = getQuorum().awaitQuorum(); - final UUID leaderId = getQuorum().getLeaderId(); + if (!isJoinedMember(token)) { - if (!isLeader(token)) { - /* - * Wait for the token to be set and the root blocks to be - * installed (if necessary). + * The quorum met on a different vote. */ - + + // Wait for the token to be set. awaitJournalToken(token, false/* awaitRootBlocks */); - - } - if (isJoinedMember(token)) { + // Resync with the quorum. + enterRunState(new ResyncTask(token)); - /* - * Make sure the initial root blocks are installed before - * proceeding if this is the first quorum meet (commit - * counter is ZERO (0)). - */ - awaitJournalToken(token, true/* awaitRootBlocks */); + } - /* - * The quorum is met, the consensus vote is our - * lastCommitTime. - */ + final UUID leaderId = getQuorum().getLeaderId(); - try { + // Transition to RunMet. + enterRunState(new RunMetTask(token, leaderId)); - journal.getHALogWriter().createLog( - journal.getRootBlockView()); - - } catch (IOException e) { - - /* - * We can not remain in the quorum if we can not write - * the HA Log file. - */ - haLog.error("CAN NOT OPEN LOG: " + e, e); - - // TODO Should be done with ShutdownTask() - server.shutdownNow(false/* destroy */); - - throw e; - - } - - // Transition to RunMet. - enterRunState(new RunMetTask(token, leaderId)); - - } else { - - // Quorum met on a different vote. - enterRunState(new ResyncTask(token)); - - } - // Done. return null; } - /** - * Spin until the journal.quorumToken is set (by the event handler). - * <p> - * Note: If - * - * @param awaitRootBlocks - * When <code>true</code> and our - * <code>rootBlock.commitCounter==0</code>, this method - * will also wait until the leader's root blocks are - * installed. This is a necessary pre-condition before - * entering {@link RunMetTask}, but it is NOT a - * pre-condition for {@link ResyncTask}. - */ - private void awaitJournalToken(final long token, - final boolean awaitRootBlocks) throws IOException, - InterruptedException { - final S leader = getLeader(token); - final IRootBlockView rbLeader = leader.getRootBlock( - new HARootBlockRequest(null/* storeUUID */)) - .getRootBlock(); - while (true) { - Thread.sleep(10/* ms */); - // while token is valid. - getQuorum().assertQuorum(token); - final long journalToken = journal.getQuorumToken(); - if (journalToken != token) - continue; - if (awaitRootBlocks) { - final IRootBlockView rbSelf = journal - .getRootBlockView(); - if (!rbSelf.getUUID().equals(rbLeader.getUUID())) { - if (rbSelf.getCommitCounter() > 0) { - final String msg = "Journal UUIDs differ @ commitCounter=" - + rbSelf.getCommitCounter() - + ", self=" - + rbSelf.getUUID() - + ",leader=" - + rbLeader.getUUID(); - haLog.error(msg); - server.shutdownNow(false/* destroy */); - throw new IllegalStateException(msg); - } - continue; - } - } - /* - * Good to go. - */ - if (haLog.isInfoEnabled()) - haLog.info("Journal quorumToken is set: awaitRootBlocks=" - + awaitRootBlocks); - break; - } - } - } /** * Task to handle a quorum meet event. + * + * FIXME Update pre-conditions on RunMet and transitions on + * SeekConsensus. */ private class RunMetTask extends RunStateCallable<Void> { @@ -1297,89 +1218,215 @@ */ throw new InterruptedException(); } - + /* - * Verify Journal is aware of the current token. + * These conditions can not be asserted here. They need to + * be put into place when the quorum meets and + * handleReplicatedWrite() needs to block until those + * pre-conditions are met before doing anything with a live + * write. */ - { + +// /* +// * Verify Journal is aware of the current token. +// */ +// { +// +// final long journalToken = journal.getQuorumToken(); +// +// if (journalToken != token) { +// throw new IllegalStateException( +// "token differs: quorum=" + token +// + ", journal=" + journalToken); +// } +// +// } +// +// if (!isLeader(token)) { +// +// /* +// * Verify that the lastCommitTime and commitCounter for +// * the leader agree with those for our local Journal. +// */ +// +// final HAGlue leader = getLeader(token); +// +// final IRootBlockView rbLeader = leader.getRootBlock( +// new HARootBlockRequest(null/* storeUUID */)) +// .getRootBlock(); +// +// final IRootBlockView rbSelf = journal +// .getRootBlockView(); +// +// if (rbSelf.getCommitCounter() != rbLeader +// .getCommitCounter()) +// throw new QuorumException("commitCounter: leader=" +// + rbLeader.getCommitCounter() + ", self=" +// + rbSelf.getCommitCounter()); +// +// if (rbSelf.getLastCommitTime() != rbLeader +// .getLastCommitTime()) +// throw new QuorumException( +// "lastCommitCounter: leader=" +// + rbLeader.getLastCommitTime() +// + ", self=" +// + rbSelf.getLastCommitTime()); +// +// // Note: Throws exception if HALogWriter is not open. +// final long logWriterCommitCounter = journal +// .getHALogWriter().getCommitCounter(); +// +// if (logWriterCommitCounter != rbSelf.getCommitCounter()) { +// +// /* +// * The HALog writer must be expecting replicated +// * cache blocks for the current commit point. +// */ +// throw new QuorumException( +// "commitCounter: logWriter=" +// + logWriterCommitCounter +// + ", self=" +// + rbSelf.getCommitCounter()); +// +// } +// +// } - final long journalToken = journal.getQuorumToken(); - - if (journalToken != token) { - throw new IllegalStateException( - "token differs: quorum=" + token - + ", journal=" + journalToken); - } - - } + } // validation of pre-conditions. - if (!isLeader(token)) { + /* + * Wait until this run state gets interrupted. + ... [truncated message content] |
From: <mar...@us...> - 2013-02-20 17:30:53
|
Revision: 6915 http://bigdata.svn.sourceforge.net/bigdata/?rev=6915&view=rev Author: martyncutcher Date: 2013-02-20 17:30:41 +0000 (Wed, 20 Feb 2013) Log Message: ----------- additional debug messages and fix for rebuild Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/pipeline/HAReceiveService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/pipeline/HAReceiveService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/pipeline/HAReceiveService.java 2013-02-20 17:18:04 UTC (rev 6914) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/pipeline/HAReceiveService.java 2013-02-20 17:30:41 UTC (rev 6915) @@ -828,7 +828,7 @@ } public Void call() throws Exception { - + // awaitAccept(); // // /* @@ -899,6 +899,9 @@ // End of stream flag. boolean EOS = false; + // for debug retain number of low level reads + int reads = 0; + while (rem > 0 && !EOS) { // block up to the timeout. @@ -934,8 +937,10 @@ + (rdlen > 0 ? rem - rdlen : rem) + " bytes remaining."); - if (rdlen > 0) + if (rdlen > 0) { + reads++; updateChk(rdlen); + } if (rdlen == -1) { // The stream is closed? @@ -1003,7 +1008,14 @@ // prepare for reading. localBuffer.flip(); - if (message.getChk() != (int) chk.getValue()) { + if (log.isTraceEnabled()) + log.trace("Prior check checksum: " + chk.getValue() + + " for position: " + localBuffer.position() + + ", limit: " + localBuffer.limit() + + ", number of reads: " + reads + ", buffer: " + + localBuffer); + + if (message.getChk() != (int) chk.getValue()) { throw new ChecksumError("msg=" + message.toString() + ", actual=" + chk.getValue()); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-20 17:18:04 UTC (rev 6914) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-20 17:30:41 UTC (rev 6915) @@ -5041,10 +5041,15 @@ // Choose the "current" root block. _rootBlock = RootBlockUtility.chooseRootBlock(rootBlock0, rootBlock1); - + haLog.warn("Installed new root blocks: rootBlock0=" + rootBlock0 + ", rootBlock1=" + rootBlock1); + // now reset the store with the root block + if (_bufferStrategy instanceof RWStrategy) + ((RWStrategy) _bufferStrategy).resetFromHARootBlock(_rootBlock); + + /* * We need to reset the backing store with the token for the new quorum. * There should not be any active writers since there was no quorum. Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-02-20 17:18:04 UTC (rev 6914) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-02-20 17:30:41 UTC (rev 6915) @@ -1895,10 +1895,11 @@ try { // Wait long enough for the RMI request to end. - Thread.sleep(250/* ms */); + Thread.sleep(500/* ms */); } catch (InterruptedException e) { - + log.warn("Shutdown interrupted", e); + // Propagate interrupt. Thread.currentThread().interrupt(); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-20 17:18:04 UTC (rev 6914) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-20 17:30:41 UTC (rev 6915) @@ -824,8 +824,8 @@ // The #of bytes remaining. long remaining = totalBytes; - // The offset (relative to the root blocks). - long offset = 0L; + // The offset from which data is retrieved. + long offset = headerSize; long sequence = 0L; @@ -853,10 +853,16 @@ haLog.debug("Sending block: sequence=" + sequence + ", offset=" + offset + ", nbytes=" + nbytes); - getBufferStrategy().sendRawBuffer(req, sequence, + final Future<?> snd = getBufferStrategy().sendRawBuffer(req, sequence, quorumToken, fileExtent, offset, nbytes, b); + + if (snd != null) { + snd.get(); // wait for data sent! + } remaining -= nbytes; + + offset += nbytes; sequence++; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java 2013-02-20 17:18:04 UTC (rev 6914) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java 2013-02-20 17:30:41 UTC (rev 6915) @@ -1360,6 +1360,8 @@ log.info(e.toString()); switch (e.getState()) { case Disconnected: + log.warn("DISCONNECTED: " + token()); + setToken(NO_QUORUM); return; case SyncConnected: break; @@ -1715,9 +1717,13 @@ final OrderedSetDifference<UUID> diff = new OrderedSetDifference<UUID>( aold, anew); for (UUID t : diff.removed()) { + if (log.isInfoEnabled()) + log.info("removing: " + t); remove(t); } for (UUID t : diff.added()) { + if (log.isInfoEnabled()) + log.info("adding: " + t); add(t); } } @@ -1727,9 +1733,13 @@ final UnorderedSetDifference<UUID> diff = new UnorderedSetDifference<UUID>( aold, anew); for (UUID t : diff.removed()) { + if (log.isInfoEnabled()) + log.info("removing: " + t); remove(t); } for (UUID t : diff.added()) { + if (log.isInfoEnabled()) + log.info("adding: " + t); add(t); } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-20 17:47:46
|
Revision: 6918 http://bigdata.svn.sourceforge.net/bigdata/?rev=6918&view=rev Author: thompsonbry Date: 2013-02-20 17:47:39 +0000 (Wed, 20 Feb 2013) Log Message: ----------- Reconciled edits with Martyn. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHAJournalServerTestCase.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-20 17:32:30 UTC (rev 6917) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-20 17:47:39 UTC (rev 6918) @@ -5041,15 +5041,15 @@ // Choose the "current" root block. _rootBlock = RootBlockUtility.chooseRootBlock(rootBlock0, rootBlock1); - + haLog.warn("Installed new root blocks: rootBlock0=" + rootBlock0 + ", rootBlock1=" + rootBlock1); // now reset the store with the root block - if (_bufferStrategy instanceof RWStrategy) - ((RWStrategy) _bufferStrategy).resetFromHARootBlock(_rootBlock); + if (_bufferStrategy instanceof IHABufferStrategy) + ((IHABufferStrategy) _bufferStrategy) + .resetFromHARootBlock(_rootBlock); - /* * We need to reset the backing store with the token for the new quorum. * There should not be any active writers since there was no quorum. Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-02-20 17:32:30 UTC (rev 6917) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-02-20 17:47:39 UTC (rev 6918) @@ -1895,10 +1895,9 @@ try { // Wait long enough for the RMI request to end. - Thread.sleep(500/* ms */); + Thread.sleep(250/* ms */); } catch (InterruptedException e) { - log.warn("Shutdown interrupted", e); // Propagate interrupt. Thread.currentThread().interrupt(); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-20 17:32:30 UTC (rev 6917) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-20 17:47:39 UTC (rev 6918) @@ -856,9 +856,7 @@ final Future<?> snd = getBufferStrategy().sendRawBuffer(req, sequence, quorumToken, fileExtent, offset, nbytes, b); - if (snd != null) { - snd.get(); // wait for data sent! - } + snd.get(); // wait for data sent! remaining -= nbytes; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java 2013-02-20 17:32:30 UTC (rev 6917) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorumImpl.java 2013-02-20 17:47:39 UTC (rev 6918) @@ -1360,8 +1360,7 @@ log.info(e.toString()); switch (e.getState()) { case Disconnected: - log.warn("DISCONNECTED: " + token()); - setToken(NO_QUORUM); + log.warn("DISCONNECTED: " + token()); return; case SyncConnected: break; @@ -1717,13 +1716,13 @@ final OrderedSetDifference<UUID> diff = new OrderedSetDifference<UUID>( aold, anew); for (UUID t : diff.removed()) { - if (log.isInfoEnabled()) - log.info("removing: " + t); + if (log.isTraceEnabled()) + log.trace("removing: " + t); remove(t); } for (UUID t : diff.added()) { - if (log.isInfoEnabled()) - log.info("adding: " + t); + if (log.isTraceEnabled()) + log.trace("adding: " + t); add(t); } } @@ -1733,13 +1732,13 @@ final UnorderedSetDifference<UUID> diff = new UnorderedSetDifference<UUID>( aold, anew); for (UUID t : diff.removed()) { - if (log.isInfoEnabled()) - log.info("removing: " + t); + if (log.isTraceEnabled()) + log.trace("removing: " + t); remove(t); } for (UUID t : diff.added()) { - if (log.isInfoEnabled()) - log.info("adding: " + t); + if (log.isTraceEnabled()) + log.trace("adding: " + t); add(t); } } Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHAJournalServerTestCase.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHAJournalServerTestCase.java 2013-02-20 17:32:30 UTC (rev 6917) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHAJournalServerTestCase.java 2013-02-20 17:47:39 UTC (rev 6918) @@ -33,6 +33,7 @@ import java.security.NoSuchAlgorithmException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -392,7 +393,7 @@ } } - }); + }, 5, TimeUnit.SECONDS); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-20 20:26:39
|
Revision: 6923 http://bigdata.svn.sourceforge.net/bigdata/?rev=6923&view=rev Author: thompsonbry Date: 2013-02-20 20:26:26 +0000 (Wed, 20 Feb 2013) Log Message: ----------- Cleaned up the HAJournalServer a bit. Simplified code in Journal.setQuorumToken(). Simplified logic in awaitJournalTokenAndRootBlocks(). This is now only invoked from pipelineSetup(). The [awaitRootBlocks] option is gone. The method no longer does RMIs unless the commitCounter is ZERO (0) AND the isFollower() is true. I have observed an error spin when attempting to restart C with A and B running. Somehow A was missing the HALog file for commitCounter=3. It was present on B, but not A. However, this error spin is very not good. We should do a shutdown if we can not correct an error, or back off on the retry rate, or something. @see https://sourceforge.net/apps/trac/bigdata/ticket/530 (HA Journal) Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-20 18:45:55 UTC (rev 6922) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-20 20:26:26 UTC (rev 6923) @@ -4926,8 +4926,7 @@ // This quorum member. final QuorumService<HAGlue> localService = quorum.getClient(); - if (localService.isJoinedMember(quorumToken) - && _rootBlock.getCommitCounter() == 0 + if (_rootBlock.getCommitCounter() == 0 && localService.isFollower(quorumToken)) { /* Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-20 18:45:55 UTC (rev 6922) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-20 20:26:26 UTC (rev 6923) @@ -27,13 +27,11 @@ import java.io.FileNotFoundException; import java.io.FilenameFilter; import java.io.IOException; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URL; import java.nio.ByteBuffer; import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.server.ServerNotActiveException; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -54,8 +52,6 @@ import net.jini.core.lookup.ServiceID; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceRegistrar; -import net.jini.export.ServerContext; -import net.jini.io.context.ClientHost; import org.apache.log4j.Logger; import org.apache.log4j.MDC; @@ -455,18 +451,18 @@ if (log.isInfoEnabled()) log.info("Starting server."); + // Setup listener that logs quorum events @ TRACE. journal.getQuorum().addListener(new QuorumListener() { - @Override public void notify(final QuorumEvent e) { if (log.isTraceEnabled()) - log.trace(e); // TODO LOG @ TRACE + log.trace(e); } }); // Setup the quorum client (aka quorum service). - quorumService = (HAQuorumService) newQuorumService(logicalServiceZPath, - serviceUUID, haGlueService, journal); + quorumService = newQuorumService(logicalServiceZPath, serviceUUID, + haGlueService, journal); // Start the quorum. journal.getQuorum().start(quorumService); @@ -637,7 +633,7 @@ * @param store * The {@link HAJournal}. */ - private QuorumServiceBase<HAGlue, HAJournal> newQuorumService( + private HAQuorumService<HAGlue, HAJournal> newQuorumService( final String logicalServiceZPath, final UUID serviceId, final HAGlue remoteServiceImpl, final HAJournal store) { @@ -825,15 +821,6 @@ * * @param runStateTask * The task for the new run state. - * - * TODO What happens if we schedule a task and we are already - * in that runState? Do we interrupt the current task and - * restart it? Is it always safe to do this? - * <p> - * Also, note that some tasks have arguments (especially - * RunMet has the token and leaderId). We would have to - * cancel an existing RunMet for a different token since they - * are otherwise not attempting to do the same thing. */ private void enterRunState(final RunStateCallable<Void> runStateTask) { @@ -884,38 +871,38 @@ } - /** - * Used to submit {@link RunStateCallable} tasks for execution from - * within the zk watcher thread. - * - * @param task - * The task to be run. - */ - private void enterRunStateFromWatcherThread( - final RunStateCallable<Void> task) { - - // Submit task to handle this event. - server.singleThreadExecutor.execute(new MonitoredFutureTask<Void>( - new SubmitRunStateTask(task))); - - } +// /** +// * Used to submit {@link RunStateCallable} tasks for execution from +// * within the zk watcher thread. +// * +// * @param task +// * The task to be run. +// */ +// private void enterRunStateFromWatcherThread( +// final RunStateCallable<Void> task) { +// +// // Submit task to handle this event. +// server.singleThreadExecutor.execute(new MonitoredFutureTask<Void>( +// new SubmitRunStateTask(task))); +// +// } +// +// /** +// * Class is used to force a run state transition based on an event +// * received in the zk watcher thread. +// */ +// private class SubmitRunStateTask implements Callable<Void> { +// private final RunStateCallable<Void> task; +// public SubmitRunStateTask(final RunStateCallable<Void> task) { +// this.task = task; +// } +// public Void call() throws Exception { +// enterRunState(task); +// return null; +// } +// } /** - * Class is used to force a run state transition based on an event - * received in the zk watcher thread. - */ - private class SubmitRunStateTask implements Callable<Void> { - private final RunStateCallable<Void> task; - public SubmitRunStateTask(final RunStateCallable<Void> task) { - this.task = task; - } - public Void call() throws Exception { - enterRunState(task); - return null; - } - } - - /** * {@inheritDoc} * <p> * Cleans up the return type. @@ -984,26 +971,26 @@ } - @Override - public void start(final Quorum<?,?> quorum) { - - if (haLog.isTraceEnabled()) - log.trace("START"); - - super.start(quorum); - - // TODO It appears to be a problem to do this here. Maybe because - // the watcher is not running yet? Could submit a task that could - // await an appropriate condition to start.... -// final QuorumActor<?, ?> actor = quorum.getActor(); -// actor.memberAdd(); -// actor.pipelineAdd(); -// actor.castVote(journal.getLastCommitTime()); - -// // Inform the Journal about the current token (if any). -// journal.setQuorumToken(quorum.token()); - - } +// @Override +// public void start(final Quorum<?,?> quorum) { +// +// if (haLog.isTraceEnabled()) +// log.trace("START"); +// +// super.start(quorum); +// +// // Note: It appears to be a problem to do this here. Maybe because +// // the watcher is not running yet? Could submit a task that could +// // await an appropriate condition to start.... +//// final QuorumActor<?, ?> actor = quorum.getActor(); +//// actor.memberAdd(); +//// actor.pipelineAdd(); +//// actor.castVote(journal.getLastCommitTime()); +// +//// // Inform the Journal about the current token (if any). +//// journal.setQuorumToken(quorum.token()); +// +// } @Override public void quorumMeet(final long token, final UUID leaderId) { @@ -1018,10 +1005,10 @@ private class QuorumMeetTask implements Callable<Void> { private final long token; - private final UUID leaderId; +// private final UUID leaderId; public QuorumMeetTask(final long token, final UUID leaderId) { this.token = token; - this.leaderId = leaderId; +// this.leaderId = leaderId; } public Void call() throws Exception { journal.setQuorumToken(token); @@ -1116,9 +1103,6 @@ * Quorum is already met. */ - // Wait for the token to be set. - awaitJournalToken(token, false/* awaitRootBlocks */); - // Resync since quorum met before we cast a vote. enterRunState(new ResyncTask(token)); @@ -1150,9 +1134,6 @@ * The quorum met on a different vote. */ - // Wait for the token to be set. - awaitJournalToken(token, false/* awaitRootBlocks */); - // Resync with the quorum. enterRunState(new ResyncTask(token)); @@ -1171,10 +1152,9 @@ } /** - * Task to handle a quorum meet event. - * - * FIXME Update pre-conditions on RunMet and transitions on - * SeekConsensus. + * While the quorum is met, accept replicated writes, laying them down + * on the HALog and the backing store, and participate in the 2-phase + * commit protocol. */ private class RunMetTask extends RunStateCallable<Void> { @@ -1219,87 +1199,9 @@ throw new InterruptedException(); } - /* - * These conditions can not be asserted here. They need to - * be put into place when the quorum meets and - * handleReplicatedWrite() needs to block until those - * pre-conditions are met before doing anything with a live - * write. - */ - -// /* -// * Verify Journal is aware of the current token. -// */ -// { -// -// final long journalToken = journal.getQuorumToken(); -// -// if (journalToken != token) { -// throw new IllegalStateException( -// "token differs: quorum=" + token -// + ", journal=" + journalToken); -// } -// -// } -// -// if (!isLeader(token)) { -// -// /* -// * Verify that the lastCommitTime and commitCounter for -// * the leader agree with those for our local Journal. -// */ -// -// final HAGlue leader = getLeader(token); -// -// final IRootBlockView rbLeader = leader.getRootBlock( -// new HARootBlockRequest(null/* storeUUID */)) -// .getRootBlock(); -// -// final IRootBlockView rbSelf = journal -// .getRootBlockView(); -// -// if (rbSelf.getCommitCounter() != rbLeader -// .getCommitCounter()) -// throw new QuorumException("commitCounter: leader=" -// + rbLeader.getCommitCounter() + ", self=" -// + rbSelf.getCommitCounter()); -// -// if (rbSelf.getLastCommitTime() != rbLeader -// .getLastCommitTime()) -// throw new QuorumException( -// "lastCommitCounter: leader=" -// + rbLeader.getLastCommitTime() -// + ", self=" -// + rbSelf.getLastCommitTime()); -// -// // Note: Throws exception if HALogWriter is not open. -// final long logWriterCommitCounter = journal -// .getHALogWriter().getCommitCounter(); -// -// if (logWriterCommitCounter != rbSelf.getCommitCounter()) { -// -// /* -// * The HALog writer must be expecting replicated -// * cache blocks for the current commit point. -// */ -// throw new QuorumException( -// "commitCounter: logWriter=" -// + logWriterCommitCounter -// + ", self=" -// + rbSelf.getCommitCounter()); -// -// } -// -// } - } // validation of pre-conditions. - /* - * Wait until this run state gets interrupted. - * - * TODO Could continue to assert our invariants, or just add zk - * event handlers to look for violations of those invariants. - */ + // Block until this run state gets interrupted. blockInterruptably(); // Done. @@ -1501,9 +1403,8 @@ // The current root block. final IRootBlockView rb = journal.getRootBlockView(); - // Use timestamp. TODO Why not working w/ TXS? + // Use timestamp. final long createTime = System.currentTimeMillis(); -// journal.getTransactionService().nextTimestamp(); // New root blocks for a (logically) empty Journal. final RootBlockUtility rbu = new RootBlockUtility(journal @@ -1619,13 +1520,17 @@ */ protected Void doRun() throws Exception { +// // Wait for the token to be set, root blocks to be valid. +// awaitJournalToken(token, true/* awaitRootBlocks */); + pipelineSetup(); + /* * Note: We need to discard any writes that might have been * buffered before we start the resynchronization of the local * store. Otherwise they could wind up flushed through by the * RWStore (for example, when handling a file extension). * - * Note: This is necessary. We do a low-level abort when we + * Note: This IS necessary. We do a low-level abort when we * install the root blocks from the quorum leader before we sync * the first commit point, but we do not do the low-level abort * if we already have the correct root blocks in place. @@ -2113,13 +2018,16 @@ getQuorum().assertQuorum(token); // Verify that we have valid root blocks - awaitJournalToken(token, true/* awaitRootBlocks */); + awaitJournalToken(token); logLock.lock(); + try { + final HALogWriter logWriter = journal.getHALogWriter(); if (!logWriter.isOpen()) { + /* * Open the HALogWriter for our current root blocks. * @@ -2128,11 +2036,16 @@ * because the historical log writes occur when we ask the * leader to send us a prior commit point in RESYNC. */ + journal.getHALogWriter().createLog( journal.getRootBlockView()); + } + } finally { + logLock.unlock(); + } } @@ -2327,11 +2240,6 @@ try { - /* - * TODO RESYNC : Review when (and where) we open and close log - * files. - */ - final HALogWriter logWriter = journal.getHALogWriter(); final long journalCommitCounter = journal.getRootBlockView() @@ -2351,9 +2259,6 @@ * of the last resync message. We are caught up. We need * to log and apply this live message, cancel the resync * task, and enter RunMet. - * - * FIXME REBUILD: Verify that we have installed the root - * blocks by this point. */ resyncTransitionToMetQuorum(msg, data); @@ -2708,23 +2613,32 @@ /** * Spin until the journal.quorumToken is set (by the event handler). * <p> - * Note: If + * Note: The {@link #quorumMeet(long, UUID)} arrives in the zookeeper + * event thread. We can not take actions that could block in that + * thread, so it is pumped into a single threaded executor. When that + * executor handles the event, it sets the token on the journal. This + * process is of necessity asynchronous with respect to the run state + * transitions for the {@link HAJournalServer}. Futher, when the local + * journal is empty (and this service is joined with the met quorum as a + * follower), setting the quorum token will also cause the root blocks + * from the leader to be installed on this service. This method is used + * to ensure that the local journal state is consistent (token is set, + * root blocks are have been copied if the local journal is empty) + * before allowing certain operations to proceed. * - * @param awaitRootBlocks - * When <code>true</code> and our - * <code>rootBlock.commitCounter==0</code>, this method - * will also wait until the leader's root blocks are - * installed. This is a necessary pre-condition before - * entering {@link RunMetTask}, but it is NOT a - * pre-condition for {@link ResyncTask}. + * @see #quorumMeet(long, UUID) + * @see HAJournal#setQuorumToken(long) */ - private void awaitJournalToken(final long token, - final boolean awaitRootBlocks) throws IOException, + private void awaitJournalToken(final long token) throws IOException, InterruptedException { - final S leader = getLeader(token); - final IRootBlockView rbLeader = leader.getRootBlock( - new HARootBlockRequest(null/* storeUUID */)) - .getRootBlock(); + /* + * Note: This is called for each HA write message received. DO NOT + * use any high latency or RMI calls unless we need to wait for the + * root blocks. That condition is detected below without any high + * latency operations. + */ + S leader = null; + IRootBlockView rbLeader = null; final long sleepMillis = 10; while (true) { // while token is valid. @@ -2734,10 +2648,23 @@ Thread.sleep(sleepMillis/* ms */); continue; } - if (awaitRootBlocks) { + if (isFollower(token)) {// if (awaitRootBlocks) { final IRootBlockView rbSelf = journal.getRootBlockView(); if (rbSelf.getCommitCounter() == 0) { - // Only wait if this is an empty Journal. + /* + * Only wait if this is an empty Journal. + */ + if (leader == null) { + /* + * RMI to the leader for its current root block + * (once). + */ + leader = getLeader(token); + rbLeader = leader + .getRootBlock( + new HARootBlockRequest(null/* storeUUID */)) + .getRootBlock(); + } if (!rbSelf.getUUID().equals(rbLeader.getUUID())) { Thread.sleep(sleepMillis/* ms */); continue; @@ -2748,8 +2675,7 @@ * Good to go. */ if (haLog.isInfoEnabled()) - haLog.info("Journal quorumToken is set: awaitRootBlocks=" - + awaitRootBlocks); + haLog.info("Journal quorumToken is set."); break; } } @@ -2917,82 +2843,82 @@ } - /** - * Sets up the {@link MDC} logging context. You should do this on every - * client facing point of entry and then call - * {@link #clearLoggingContext()} in a <code>finally</code> clause. You - * can extend this method to add additional context. - * <p> - * This implementation adds the following parameters to the {@link MDC}. - * <dl> - * <dt>serviceName</dt> - * <dd>The serviceName is typically a configuration property for the - * service. This datum can be injected into log messages using - * <em>%X{serviceName}</em> in your log4j pattern layout.</dd> - * <dt>serviceUUID</dt> - * <dd>The serviceUUID is, in general, assigned asynchronously by the - * service registrar. Once the serviceUUID becomes available it will be - * added to the {@link MDC}. This datum can be injected into log - * messages using <em>%X{serviceUUID}</em> in your log4j pattern layout. - * </dd> - * <dt>hostname</dt> - * <dd>The hostname statically determined. This datum can be injected - * into log messages using <em>%X{hostname}</em> in your log4j pattern - * layout.</dd> - * <dt>clientname - * <dt> - * <dd>The hostname or IP address of the client making the request.</dd> - * </dl> - * Note: {@link InetAddress#getHostName()} is used. This method makes a - * one-time best effort attempt to resolve the host name from the - * {@link InetAddress}. - */ - private void setupLoggingContext() { +// /** +// * Sets up the {@link MDC} logging context. You should do this on every +// * client facing point of entry and then call +// * {@link #clearLoggingContext()} in a <code>finally</code> clause. You +// * can extend this method to add additional context. +// * <p> +// * This implementation adds the following parameters to the {@link MDC}. +// * <dl> +// * <dt>serviceName</dt> +// * <dd>The serviceName is typically a configuration property for the +// * service. This datum can be injected into log messages using +// * <em>%X{serviceName}</em> in your log4j pattern layout.</dd> +// * <dt>serviceUUID</dt> +// * <dd>The serviceUUID is, in general, assigned asynchronously by the +// * service registrar. Once the serviceUUID becomes available it will be +// * added to the {@link MDC}. This datum can be injected into log +// * messages using <em>%X{serviceUUID}</em> in your log4j pattern layout. +// * </dd> +// * <dt>hostname</dt> +// * <dd>The hostname statically determined. This datum can be injected +// * into log messages using <em>%X{hostname}</em> in your log4j pattern +// * layout.</dd> +// * <dt>clientname +// * <dt> +// * <dd>The hostname or IP address of the client making the request.</dd> +// * </dl> +// * Note: {@link InetAddress#getHostName()} is used. This method makes a +// * one-time best effort attempt to resolve the host name from the +// * {@link InetAddress}. +// */ +// private void setupLoggingContext() { +// +// try { +// +// // Note: This _is_ a local method call. +// final ServiceID serviceUUID = server.getServiceID(); +// +// // Will be null until assigned by the service registrar. +// +// if (serviceUUID != null) { +// +// MDC.put("serviceUUID", serviceUUID); +// +// } +// +// MDC.put("serviceName", server.getServiceName()); +// +// MDC.put("hostname", server.getHostName()); +// +// try { +// +// final InetAddress clientAddr = ((ClientHost) ServerContext +// .getServerContextElement(ClientHost.class)) +// .getClientHost(); +// +// MDC.put("clientname", clientAddr.getHostName()); +// +// } catch (ServerNotActiveException e) { +// +// /* +// * This exception gets thrown if the client has made a +// * direct (vs RMI) call so we just ignore it. +// */ +// +// } +// +// } catch (Throwable t) { +// +// /* +// * Ignore. +// */ +// +// } +// +// } - try { - - // Note: This _is_ a local method call. - final ServiceID serviceUUID = server.getServiceID(); - - // Will be null until assigned by the service registrar. - - if (serviceUUID != null) { - - MDC.put("serviceUUID", serviceUUID); - - } - - MDC.put("serviceName", server.getServiceName()); - - MDC.put("hostname", server.getHostName()); - - try { - - final InetAddress clientAddr = ((ClientHost) ServerContext - .getServerContextElement(ClientHost.class)) - .getClientHost(); - - MDC.put("clientname", clientAddr.getHostName()); - - } catch (ServerNotActiveException e) { - - /* - * This exception gets thrown if the client has made a - * direct (vs RMI) call so we just ignore it. - */ - - } - - } catch (Throwable t) { - - /* - * Ignore. - */ - - } - - } - /** * Clear the logging context. */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-21 15:19:24
|
Revision: 6924 http://bigdata.svn.sourceforge.net/bigdata/?rev=6924&view=rev Author: thompsonbry Date: 2013-02-21 15:19:09 +0000 (Thu, 21 Feb 2013) Log Message: ----------- Refactored the HALog file extension onto the IHALogReader interface (in both the halog and althalog packages). This data was being declared in several different locations. Added declaration for the quorum/backup znode to ZKQuorum in support of HA backups. Added QuorumBackupState object in support of HA backups. Modified purgeHALogs() to check the data on the quorum/backup znode. When that znode exists, it will not delete HALogs unless they have been backed up. Added code to HAJournalServer.serviceJoin() to purge HALogs (but not the current HALog) when we transition to a fully met quorum. This allows the purge to occur before we reach a commit point. This code is conditionally disabled for now. Additional cleanup and documentation on HAJournalServer and the HA transition flowcharts. Removed the incremental option from IHASyncRequest. This is no longer required since we have restructured how we do RESYNC. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/IHALogReader.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogReader.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HALogRequest.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HARebuildRequest.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASyncRequest.java branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorum.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java Added Paths: ----------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/QuorumBackupState.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogFile.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -64,7 +64,7 @@ */ public class HALogFile { - public static final String HA_LOG_EXT = ".ha-log"; +// public static final String HA_LOG_EXT = ".ha-log"; /** * Logger for HA events. @@ -175,7 +175,7 @@ m_callback = callback; final File hadir = m_callback.getHALogDir(); m_haLogFile = new File(hadir, getHALogFileName(rbv.getCommitCounter()) - + HA_LOG_EXT); + + IHALogReader.HA_LOG_EXT); if (m_haLogFile.exists()) throw new IllegalStateException("File already exists: " @@ -675,7 +675,7 @@ final Formatter f = new Formatter(sb); - f.format("%020d" + HA_LOG_EXT, commitCounter); + f.format("%020d" + IHALogReader.HA_LOG_EXT, commitCounter); f.flush(); f.close(); @@ -930,8 +930,6 @@ /** Current write cache block sequence counter. */ private long m_nextSequence = 0; - public static final String HA_LOG_EXT = ".ha-log"; - private void assertOpen() { if (!isOpen()) Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -337,7 +337,7 @@ } - return name.endsWith(HALogFile.HA_LOG_EXT); + return name.endsWith(IHALogReader.HA_LOG_EXT); } }); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/IHALogReader.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/IHALogReader.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/IHALogReader.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -41,6 +41,11 @@ */ public interface IHALogReader { + /** + * The filename extension used for the HALog files. + */ + public static final String HA_LOG_EXT = ".ha-log"; + /** * Closes the Reader. * Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogReader.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogReader.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogReader.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -423,7 +423,7 @@ } - return name.endsWith(HALogWriter.HA_LOG_EXT); + return name.endsWith(IHALogReader.HA_LOG_EXT); } }); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -121,7 +121,7 @@ /** state lock **/ final private ReentrantReadWriteLock m_stateLock = new ReentrantReadWriteLock(); - public static final String HA_LOG_EXT = ".ha-log"; +// public static final String HA_LOG_EXT = ".ha-log"; /** current write point on the channel. */ private long m_position = headerSize0; @@ -199,7 +199,7 @@ final Formatter f = new Formatter(sb); - f.format("%020d" + HA_LOG_EXT, commitCounter); + f.format("%020d" + IHALogReader.HA_LOG_EXT, commitCounter); f.flush(); f.close(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/IHALogReader.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -39,6 +39,11 @@ */ public interface IHALogReader { + /** + * The filename extension used for the HALog files. + */ + public static final String HA_LOG_EXT = ".ha-log"; + /** * Closes the Reader. * Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HALogRequest.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HALogRequest.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HALogRequest.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -34,7 +34,7 @@ private final UUID serviceId; private final long commitCounter; - private final boolean incremental; +// private final boolean incremental; /** * @param serviceId @@ -43,12 +43,13 @@ * The commit counter used to identify the desired commit point * (the commit counter of the closing root block). */ - public HALogRequest(final UUID serviceId, final long commitCounter, - final boolean incremental) { + public HALogRequest(final UUID serviceId, final long commitCounter +// , final boolean incremental + ) { this.serviceId = serviceId; this.commitCounter = commitCounter; - this.incremental = incremental; +// this.incremental = incremental; } @@ -69,15 +70,17 @@ public String toString() { return getClass() + "{serviceId=" + getServiceId() + ", commitCounter=" - + getCommitCounter() + ", incremental=" + isIncremental() + "}"; + + getCommitCounter() + +// ", incremental=" + isIncremental() + + "}"; } - @Override - public boolean isIncremental() { - - return incremental; - - } +// @Override +// public boolean isIncremental() { +// +// return incremental; +// +// } } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HARebuildRequest.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HARebuildRequest.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HARebuildRequest.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -53,16 +53,17 @@ public String toString() { - return getClass() + "{serviceId=" + getServiceId() + ", incremental=" - + isIncremental() + "}"; + return getClass() + "{serviceId=" + getServiceId() + // + ", incremental=" + isIncremental() + + "}"; } - @Override - final public boolean isIncremental() { - - return false; - - } +// @Override +// final public boolean isIncremental() { +// +// return false; +// +// } } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASyncRequest.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASyncRequest.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHASyncRequest.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -33,12 +33,12 @@ */ public interface IHASyncRequest extends IHAMessage { - /** - * When <code>true</code> the request is part of an incremental - * re-synchronization. When <code>false</code> the request is part of - * a total re-build. - */ - boolean isIncremental(); +// /** +// * When <code>true</code> the request is part of an incremental +// * re-synchronization. When <code>false</code> the request is part of +// * a total re-build. +// */ +// boolean isIncremental(); /** * The UUID of the service that issued this request. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -1013,10 +1013,18 @@ lock.lock(); try { - + + if (joined.size() != k) { + + // Quorum is not fully met. + return false; + + } + + // Verify token. assertQuorum(token); - return joined.size() == k; + return true; } finally { Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -29,6 +29,7 @@ import java.net.InetSocketAddress; import java.net.ServerSocket; import java.nio.ByteBuffer; +import java.rmi.Remote; import java.util.Arrays; import java.util.LinkedList; import java.util.List; @@ -72,6 +73,7 @@ import com.bigdata.ha.msg.IHAWriteMessage; import com.bigdata.ha.msg.IHAWriteSetStateRequest; import com.bigdata.ha.msg.IHAWriteSetStateResponse; +import com.bigdata.io.SerializerUtil; import com.bigdata.jini.start.config.ZookeeperClientConfig; import com.bigdata.journal.IRootBlockView; import com.bigdata.quorum.AbstractQuorumMember; @@ -79,6 +81,8 @@ import com.bigdata.quorum.QuorumEvent; import com.bigdata.quorum.QuorumException; import com.bigdata.quorum.QuorumListener; +import com.bigdata.quorum.zk.QuorumBackupState; +import com.bigdata.quorum.zk.ZKQuorum; import com.bigdata.quorum.zk.ZKQuorumImpl; import com.bigdata.service.jini.JiniClient; import com.bigdata.service.jini.JiniClientConfig; @@ -1047,6 +1051,33 @@ // FIXME Install the root blocks (atomically or as dups of the current root block). // installRootBlocks(resp.getRootBlock0(), resp.getRootBlock1()); + /* + * TODO After we run the backup utility, we need to ensure that + * the znode exists against which the backup will be registered. + * Then we need to write in the values of {inc,full} for the + * most recent incremental and full backups (depending on which + * one we just did). + */ + final long inc = -1; // TODO set this. + final long full = -1; // TODO set this. + final byte[] data = SerializerUtil + .serialize(new QuorumBackupState(inc, full)); + final String zpath = logicalServiceZPath + "/" + + ZKQuorum.QUORUM + "/" + ZKQuorum.QUORUM_BACKUP; + // Ensure exists. + try { + zka.getZookeeper().create( + zpath, data, + zkClientConfig.acl, CreateMode.PERSISTENT); + } catch (NodeExistsException ex) { + + /* + * Since it already exists, we just update it's state now. + */ + zka.getZookeeper().setData(zpath, data, -1/* version */); + + } + // Done return null; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -476,7 +476,7 @@ if (f.isDirectory()) return true; - return f.getName().endsWith(HALogWriter.HA_LOG_EXT); + return f.getName().endsWith(IHALogReader.HA_LOG_EXT); } }); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -56,6 +56,7 @@ import org.apache.log4j.Logger; import org.apache.log4j.MDC; import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NodeExistsException; import org.apache.zookeeper.data.ACL; import org.eclipse.jetty.server.Server; @@ -83,6 +84,7 @@ import com.bigdata.ha.msg.IHAWriteSetStateResponse; import com.bigdata.io.DirectBufferPool; import com.bigdata.io.IBufferAccess; +import com.bigdata.io.SerializerUtil; import com.bigdata.io.writecache.WriteCache; import com.bigdata.jini.start.config.ZookeeperClientConfig; import com.bigdata.jini.util.JiniUtil; @@ -94,6 +96,8 @@ import com.bigdata.quorum.QuorumEvent; import com.bigdata.quorum.QuorumException; import com.bigdata.quorum.QuorumListener; +import com.bigdata.quorum.zk.QuorumBackupState; +import com.bigdata.quorum.zk.ZKQuorum; import com.bigdata.quorum.zk.ZKQuorumImpl; import com.bigdata.rdf.sail.webapp.ConfigParams; import com.bigdata.rdf.sail.webapp.NanoSparqlServer; @@ -531,9 +535,9 @@ * Ensure that the HAQuorumService will not attempt to cure any * serviceLeave or related actions. * - * TODO If we properly enter a ShutdownTask run state then we would - * not have to do this since it will already be in the Shutdown - * runstate. + * TODO SHUTDOWN: If we properly enter a ShutdownTask run state then + * we would not have to do this since it will already be in the + * Shutdown runstate. */ quorumService.runStateRef .set(HAQuorumService.RunStateEnum.Shutdown); @@ -674,7 +678,7 @@ RunMet, Resync, Rebuild, - Shutdown; // TODO We are not using this systematically (no ShutdownTask for this run state). + Shutdown; // TODO SHUTDOWN: We are not using this systematically (no ShutdownTask for this run state). } private final AtomicReference<RunStateEnum> runStateRef = new AtomicReference<RunStateEnum>( @@ -1039,8 +1043,34 @@ return null; } } - + /** + * If there is a fully met quorum, then we can purge all HA logs + * <em>EXCEPT</em> the current one. + */ + @Override + public void serviceJoin() { + + super.serviceJoin(); + + if (false) { + /* + * TODO BACKUP: Purge of HALog files on a fully met quorum is + * current disabled. Enable, but review implications in more + * depth first. + */ + final long token = getQuorum().token(); + + if (getQuorum().isQuorumFullyMet(token)) { + + purgeHALogs(false/* includeCurrent */); + + } + } + + } + + /** * Task to handle a quorum break event. */ private class SeekConsensusTask extends RunStateCallable<Void> { @@ -1233,16 +1263,16 @@ @Override protected Void doRun() throws Exception { /* - * FIXME Enable restore and test. There is a problem with - * replication of the WORM HALog files and backup/restore. The - * WORM HALog files currently do not have the actual data on the - * leader. This makes some of the code messier and also means - * that the HALog files can not be binary equals on the leader - * and follower and could cause problems if people harvest them - * from the file system directly rather than through - * sendHALogFile() since they will be missing the necessary - * state in the file system if they were put there by the - * leader. + * FIXME RESTORE: Enable restore and test. There is a problem + * with replication of the WORM HALog files and backup/restore. + * The WORM HALog files currently do not have the actual data on + * the leader. This makes some of the code messier and also + * means that the HALog files can not be binary equals on the + * leader and follower and could cause problems if people + * harvest them from the file system directly rather than + * through sendHALogFile() since they will be missing the + * necessary state in the file system if they were put there by + * the leader. */ if(false) while (true) { @@ -1625,7 +1655,7 @@ * HALog files that we need. However, REBUILD is still * semantically correct so long as we restart the procedure. * - * TODO RESYNC : It is possible to go to another service in the + * TODO RESYNC: It is possible to go to another service in the * met quorum for the same log file, but it needs to be a * service that is UPSTREAM of this service. */ @@ -1742,8 +1772,9 @@ ft = leader .sendHALogForWriteSet(new HALogRequest( - server.serviceUUID, closingCommitCounter, - true/* incremental */)); + server.serviceUUID, closingCommitCounter +// , true/* incremental */ + )); // Wait until all write cache blocks are received. ft.get(); @@ -2070,13 +2101,8 @@ } - // The current root block on this service. - final long commitCounter = journal.getRootBlockView() - .getCommitCounter(); + if (req != null && req instanceof IHARebuildRequest) { - if (req != null && !req.isIncremental() - && req instanceof IHARebuildRequest) { - /* * This message and payload are part of a ground up service * rebuild (disaster recovery from the quorum) rather than @@ -2135,17 +2161,22 @@ final RunStateEnum runState = runStateRef.get(); - if (RunStateEnum.Resync.equals(runState) - || RunStateEnum.Rebuild.equals(runState)) { + if (RunStateEnum.Resync.equals(runState)) { /* * If we are resynchronizing, then pass ALL messages (both * live and historical) into handleResyncMessage(). + * + * Note: This method handles the transition into the met + * quorum when we observe a LIVE message that is the + * successor of the last received HISTORICAL message. This + * is the signal that we are caught up on the writes on the + * met quorum and may join. */ handleResyncMessage((IHALogRequest) req, msg, data); - } else if (commitCounter == msg.getCommitCounter() + } else if (journal.getRootBlockView().getCommitCounter() == msg.getCommitCounter() && isJoinedMember(msg.getQuorumToken())) { /* @@ -2242,17 +2273,14 @@ final HALogWriter logWriter = journal.getHALogWriter(); - final long journalCommitCounter = journal.getRootBlockView() - .getCommitCounter(); - if (req == null) { /* * Live message. */ - if (msg.getCommitCounter() == journalCommitCounter - && msg.getSequence() + 1 == logWriter.getSequence()) { + if ((msg.getCommitCounter() == journal.getRootBlockView().getCommitCounter()) + && ((msg.getSequence() + 1) == logWriter.getSequence())) { /* * We just received a live message that is the successor @@ -2378,30 +2406,9 @@ */ getActor().serviceJoin(); - /* - * - */ - + // Transition to RunMet. enterRunState(new RunMetTask(token, leaderId)); - // /* - // * TODO RESYNC : If there is a fully met quorum, then we can purge - // * all HA logs *EXCEPT* the current one. However, in order - // * to have the same state on each node, we really need to - // * make this decision when a service observes the - // * SERVICE_JOIN event that results in a fully met quorum. - // * That state change will be globally visible. If we do - // this - // * here, then only the service that was resynchronizing - // will - // * wind up purging its logs. - // */ - // if (getQuorum().isQuorumFullyMet()) { - // - // purgeHALogs(false/* includeCurrent */); - // - // } - } /** @@ -2539,6 +2546,33 @@ * {@inheritDoc} * <p> * Destroys the HA log files in the HA log directory. + * + * TODO BACKUP: This already parses the closing commit counter out of + * the HALog filename. To support backup, we MUST NOT delete an HALog + * file that is being retained by the backup retention policy. This will + * be coordinated through zookeeper. + * + * <pre> + * logicalServiceZPath/backedUp {inc=CC;full=CC} + * </pre> + * + * where + * <dl> + * <dt>inc</dt> + * <dd>The commitCounter of the last incremental backup that was + * captured</dd> + * <dt>full</dt> + * <dd>The commitCounter of the last full backup that was captured.</dd> + * </dl> + * + * IF this znode exists, then backups are being captured. When backups + * are being captured, then HALog files may only be removed once they + * have been captured by a backup. The znode is automatically created by + * the backup utility. If you destroy the znode, it will no longer + * assume that backups are being captured until the next time you run + * the backup utility. + * + * @see HABackupManager */ @Override public void purgeHALogs(final boolean includeCurrent) { @@ -2547,35 +2581,116 @@ try { - final File logDir = journal.getHALogDir(); + final QuorumBackupState backupState; + { + QuorumBackupState tmp = null; + try { + final String zpath = server.logicalServiceZPath + "/" + + ZKQuorum.QUORUM + "/" + + ZKQuorum.QUORUM_BACKUP; + tmp = (QuorumBackupState) SerializerUtil + .deserialize(server.zka + .getZookeeper() + .getData(zpath, false/* watch */, null/* stat */)); + } catch (KeeperException.NoNodeException ex) { + // ignore. + } catch (KeeperException e) { + // log @ error and ignore. + log.error(e); + } catch (InterruptedException e) { + // Propagate interrupt. + Thread.currentThread().interrupt(); + return; + } + backupState = tmp; + } + + /* + * List the HALog files for this service. + */ + final File[] logFiles; + { - final File[] files = logDir.listFiles(new FilenameFilter() { + final File currentLogFile = journal.getHALogWriter() + .getFile(); - @Override - public boolean accept(final File dir, final String name) { + final String currentLogFileName = currentLogFile == null ? null + : currentLogFile.getName(); - return name.endsWith(HALogWriter.HA_LOG_EXT); + final File logDir = journal.getHALogDir(); - } - }); + logFiles = logDir.listFiles(new FilenameFilter() { + /** + * Return <code>true</code> iff the file is an HALog + * file that should be deleted. + * + * @param name + * The name of that HALog file (encodes the + * commitCounter). + */ + @Override + public boolean accept(final File dir, final String name) { + + if (!name.endsWith(IHALogReader.HA_LOG_EXT)) { + // Not an HALog file. + return false; + } + + if (!includeCurrent && currentLogFile != null + && name.equals(currentLogFileName)) { + /* + * The caller requested that we NOT purge the + * current HALog, and this is it. + */ + return false; + } + + // Strip off the filename extension. + final String logFileBaseName = name.substring(0, + IHALogReader.HA_LOG_EXT.length()); + + // Closing commitCounter for HALog file. + final long logCommitCounter = Long + .parseLong(logFileBaseName); + + if (backupState != null) { + /* + * Backups are being made. + * + * When backups are being made, we DO NOT delete + * HALog files for commit points GT this + * commitCounter. + */ + if (logCommitCounter > backupState.inc()) { + /* + * Backups are being made and this HALog + * file has not been backed up yet. + */ + return false; + } + } + + // This HALog file MAY be deleted. + return true; + + } + }); + + } + int ndeleted = 0; long totalBytes = 0L; - final File currentFile = journal.getHALogWriter().getFile(); + for (File logFile : logFiles) { - for (File file : files) { + // #of bytes in that HALog file. + final long len = logFile.length(); - final long len = file.length(); + if (!logFile.delete()) { - final boolean delete = includeCurrent - || currentFile != null - && file.getName().equals(currentFile.getName()); + haLog.warn("COULD NOT DELETE FILE: " + logFile); - if (delete && !file.delete()) { - - haLog.warn("COULD NOT DELETE FILE: " + file); - continue; } Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/QuorumBackupState.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/QuorumBackupState.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/QuorumBackupState.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -0,0 +1,118 @@ +/** + +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 Jun 29, 2010 + */ + +package com.bigdata.quorum.zk; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +/** + * A object whose state indicates the commitCounter of (a) the last full backup; + * and (b) the last incremental backup for the highly available logical service + * associated with this quorum. + * + * @see ZKQuorum#QUORUM_BACKUP + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id: QuorumServiceState.java 4069 2011-01-09 20:58:02Z thompsonbry $ + */ +public class QuorumBackupState implements Externalizable { + + private static final long serialVersionUID = 1L; + + /** + * The initial version. The version appears as the first byte. The remaining + * fields for this version are: the {@link #serviceUUID} written as the most + * significant bits (long) followed by least significant bits (long). + */ + protected static final byte VERSION0 = 0; + + private long inc, full; + + public String toString() { + return getClass().getName() + // + "{inc=" + inc + ", full=" + full + // + "}"; + } + + /** + * Deserialization constructor. + */ + public QuorumBackupState() { + + } + + public QuorumBackupState(final long inc, final long full) { + + if (inc <= 0L) + throw new IllegalArgumentException(); + if (full <= 0L) + throw new IllegalArgumentException(); + + this.inc = inc; + this.full = full; + + } + + public long inc() { + return inc; + } + + public long full() { + return full; + } + + public void readExternal(final ObjectInput in) throws IOException, + ClassNotFoundException { + + final byte version = in.readByte(); + + switch (version) { + case VERSION0: { + inc = in.readLong(); + full = in.readLong(); + break; + } + default: + throw new IOException("Unknown version: " + version); + } + + } + + public void writeExternal(final ObjectOutput out) throws IOException { + + out.write(VERSION0); + + out.writeLong(inc); + + out.writeLong(full); + + } + +} Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorum.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorum.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorum.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -187,4 +187,18 @@ */ String QUORUM_PIPELINE_PREFIX = "pipeline"; + /** + * The name of the znode whose data reflects the commit counters associated + * with the most recent full and incremental backups of the logical service + * associated with this quorum. + * <p> + * Note: This znode does not exist unless backups are being performed. If it + * exists, then HALog files (each of which corresponds to a single commit + * point) will not be purged unless their commit point is LT the last + * incremental or full backup recorded in this znode. + * + * @see QuorumBackupState + */ + String QUORUM_BACKUP = "backup"; + } Modified: branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java =================================================================== --- branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java 2013-02-20 20:26:26 UTC (rev 6923) +++ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java 2013-02-21 15:19:09 UTC (rev 6924) @@ -35,7 +35,7 @@ import com.bigdata.ha.HAGlue; import com.bigdata.ha.QuorumService; -import com.bigdata.ha.halog.HALogWriter; +import com.bigdata.ha.halog.IHALogReader; import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.IIndexManager; import com.bigdata.quorum.zk.ZKQuorumImpl; @@ -147,7 +147,7 @@ @Override public boolean accept(File dir, String name) { return name - .endsWith(HALogWriter.HA_LOG_EXT); + .endsWith(IHALogReader.HA_LOG_EXT); } }); int nfiles = 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2013-02-22 16:16:01
|
Revision: 6926 http://bigdata.svn.sourceforge.net/bigdata/?rev=6926&view=rev Author: martyncutcher Date: 2013-02-22 16:15:50 +0000 (Fri, 22 Feb 2013) Log Message: ----------- remove argument to purgeHAlogs since it is never appropriate to remove the open halog file Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA2JournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java Property Changed: ---------------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/ Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -164,10 +164,14 @@ * moment, we no longer require these log files to resynchronize any * service. * + * NOTE: We should never remove the open log file + * + * This parameter has been removed + * * @param includeCurrent * When <code>true</code>, the current HA Log file will also be * purged. */ - void purgeHALogs(boolean includeCurrent); + void purgeHALogs(); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -142,9 +142,9 @@ } @Override - public void purgeHALogs(final boolean includeCurrent) { + public void purgeHALogs() { - QuorumServiceBase.this.purgeHALogs(includeCurrent); + QuorumServiceBase.this.purgeHALogs(); } @@ -266,7 +266,7 @@ * Note: The default implementation is a NOP. */ @Override - public void purgeHALogs(final boolean includeCurrent) { + public void purgeHALogs() { // NOP Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -234,19 +234,12 @@ * * @throws IOException */ - public void removeAllLogFiles(boolean includeCurrent) { + public void removeAllLogFiles() { m_currentLock.lock(); try { - if (includeCurrent && m_current != null) - try { - m_current.disable(); - } catch (IOException e) { - throw new RuntimeException("Unable to disable current log file", e); - } - - final File current = !includeCurrent ? getCurrentFile() : null; + // No longer disables the current log file - removeAllLogFiles(m_halogdir, current); + removeAllLogFiles(m_halogdir, getCurrentFile()); } finally { m_currentLock.unlock(); } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/halog/HALogWriter.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -160,7 +160,7 @@ } public boolean isOpen() { - return m_state != null; + return m_state != null && !m_state.isCommitted(); } /** Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -5660,10 +5660,10 @@ /* * The HA log files are purged on each node any time * the quorum is fully met and goes through a commit - * point. + * point. Leaving only the current open log file. */ - localService.purgeHALogs(true/* includeCurrent */); + localService.purgeHALogs(); } Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -371,9 +371,9 @@ } @Override - public void purgeHALogs(final boolean includeCurrent) { + public void purgeHALogs() { - MyMockQuorumMember.this.purgeHALogs(includeCurrent); + MyMockQuorumMember.this.purgeHALogs(); } @@ -465,7 +465,7 @@ } @Override - public void purgeHALogs(final boolean includeCurrent) { + public void purgeHALogs() { // NOP Property changes on: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha ___________________________________________________________________ Added: svn:ignore + HAJournalAlt.java HAJournalServerAlt.java HAJournal.java.old.txt HAJournal.new.txt HAJournalServer.java.mine HAJournalServer.java.old.txt HAJournalServer.java.r6895 HAJournalServer.java.r6896 HAJournalServer.new.txt Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -702,7 +702,7 @@ } @Override - public void purgeHALogs(boolean includeCurrent) { + public void purgeHALogs() { // TODO Auto-generated method stub } Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -1033,6 +1033,8 @@ private class QuorumBreakTask implements Callable<Void> { public Void call() throws Exception { + getQuorum().getActor().serviceLeave(); + journal.setQuorumToken(Quorum.NO_QUORUM); try { journal.getHALogWriter().disable(); @@ -1063,13 +1065,13 @@ if (getQuorum().isQuorumFullyMet(token)) { - purgeHALogs(false/* includeCurrent */); + purgeHALogs(); } } } - + /** * Task to handle a quorum break event. */ @@ -1274,7 +1276,7 @@ * necessary state in the file system if they were put there by * the leader. */ - if(false) + if(true) while (true) { long commitCounter = journal.getRootBlockView() @@ -2588,7 +2590,7 @@ * @see HABackupManager */ @Override - public void purgeHALogs(final boolean includeCurrent) { + public void purgeHALogs() { logLock.lock(); @@ -2650,7 +2652,8 @@ return false; } - if (!includeCurrent && currentLogFile != null + // filter out the current log file + if (currentLogFile != null && name.equals(currentLogFileName)) { /* * The caller requested that we NOT purge the Property changes on: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha ___________________________________________________________________ Added: svn:ignore + log4j.properties logging.properties Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -458,8 +458,34 @@ safeDestroy(serverC, serviceListenerC); } + protected void shutdownA() throws IOException { + safeShutdown(serverA, serviceListenerA, true); + + serverA = null; + serviceListenerA = null; + } + + protected void shutdownB() throws IOException { + safeShutdown(serverB, serviceListenerB, true); + + serverB = null; + serviceListenerB = null; + } + + protected void shutdownC() throws IOException { + safeShutdown(serverC, serviceListenerC, true); + + serverC = null; + serviceListenerC = null; + } + private void safeShutdown(final HAGlue haGlue, final ServiceListener serviceListener) { + safeShutdown(haGlue, serviceListener, false); // not shutdownNow by default + } + + private void safeShutdown(final HAGlue haGlue, + final ServiceListener serviceListener, final boolean now) { if (haGlue == null) return; @@ -469,7 +495,10 @@ final UUID serviceId = haGlue.getServiceUUID(); // Shutdown the remote service. - ((RemoteDestroyAdmin) haGlue).shutdown(); + if (now) + ((RemoteDestroyAdmin) haGlue).shutdownNow(); + else + ((RemoteDestroyAdmin) haGlue).shutdown(); awaitServiceGone(serviceId, haGlue, serviceListener); Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA2JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA2JournalServer.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA2JournalServer.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -29,6 +29,8 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; +import org.apache.log4j.Logger; + import com.bigdata.ha.HAGlue; import com.bigdata.ha.msg.HARootBlockRequest; import com.bigdata.journal.IRootBlockView; @@ -47,6 +49,8 @@ */ public class TestHA2JournalServer extends AbstractHA3JournalServerTestCase { + protected static final Logger haLog = Logger.getLogger("com.bigdata.haLog"); + public TestHA2JournalServer() { } @@ -135,6 +139,8 @@ * for the follower and verify that the quorum meets again. */ public void testStartAB_BounceFollower() throws Exception { + + haLog.warn("Starting AB_BounceFolloer test"); HAGlue serverA = startA(); HAGlue serverB = startB(); @@ -169,7 +175,12 @@ serverA.bounceZookeeperConnection().get(); } - + + // Okay, is the problem that the quorum doesn't break? + // assertFalse(quorum.isQuorumMet()); + + // Right so the Quorum is not met, but the follower deosn't seem to know it's broken + // Wait for the quorum to break and then meet again. final long token2 = awaitNextQuorumMeet(token1); Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-02-21 16:48:04 UTC (rev 6925) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-02-22 16:15:50 UTC (rev 6926) @@ -27,6 +27,9 @@ package com.bigdata.journal.jini.ha; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.util.LinkedList; import java.util.List; @@ -39,6 +42,7 @@ import com.bigdata.ha.HAGlue; import com.bigdata.ha.halog.HALogWriter; import com.bigdata.ha.msg.HARootBlockRequest; +import com.bigdata.journal.jini.ha.HAJournalServer.AdministrableHAGlueService; import com.bigdata.quorum.Quorum; import com.bigdata.rdf.sail.webapp.client.RemoteRepository; @@ -456,7 +460,8 @@ } /** - * Tests that halog files are generated and identical + * Tests that halog files are generated and identical, and that + * when a server is shutdown its logs remain */ public void testStartAB_halog() { fail("write test"); @@ -1097,6 +1102,30 @@ } } + private void copyFiles(File src, File dst) throws IOException { + final File[] files = src.listFiles(); + log.warn("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath() + ", files: " + files.length); + if (files != null) { + for (File srcFile: files) { + final File dstFile = new File(dst, srcFile.getName()); + log.info("Copying " + srcFile.getAbsolutePath() + " to " + dstFile.getAbsolutePath()); + final FileInputStream instr = new FileInputStream(srcFile); + final FileOutputStream outstr = new FileOutputStream(dstFile); + + final byte[] buf = new byte[8192]; + while (true) { + final int len = instr.read(buf); + if (len == -1) + break; + + outstr.write(buf, 0, len); + } + + outstr.close(); + instr.close(); + } + } + } /** * Test Rebuild of early starting C service where service from previously fully met quorum is not * started. @@ -1106,6 +1135,117 @@ } /** + * Test Restore by: + * starting ABC + * drop C + * run transaction through AB + * drop A + * start C + * Restore + * Meet on BC + * start A + * Fully Meet + * @throws Exception + */ + public void testABC_Restore() throws Exception { + // Start 3 services, sleeps to ensure sequence. + final HAGlue serverA = startA(); + //Thread.sleep(100); + final HAGlue serverB = startB(); + //Thread.sleep(100); + final HAGlue serverC = startC(); + + // Wait for a quorum meet. + final long token = quorum.awaitQuorum(awaitQuorumTimeout, + TimeUnit.MILLISECONDS); + + // Verify KB exists. + awaitKBExists(serverA); + + + /* + * Now go through a commit point with a met quorum. The HALog + * files should be retained at that commit point. + */ + { + + final StringBuilder sb = new StringBuilder(); + sb.append("DROP ALL;\n"); + sb.append("PREFIX dc: <http://purl.org/dc/elements/1.1/>\n"); + sb.append("INSERT DATA {\n"); + sb.append(" <http://example/book1> dc:title \"A new book\" ;\n"); + sb.append(" dc:creator \"A.N.Other\" .\n"); + sb.append("}\n"); + + final String updateStr = sb.toString(); + + final HAGlue leader = quorum.getClient().getLeader(token); + + // Verify quorum is still valid. + quorum.assertQuorum(token); + + getRemoteRepository(leader).prepareUpdate(updateStr).evaluate(); + + } + + // now shutdown C (not destroy) + shutdownC(); + + log.warn("CHECK OPEN LOGS ON A B"); + + + /* + * Now go through a commit point with a met quorum. The HALog + * files should be retained at that commit point. + */ + if (true/*new commit state*/) { + + final StringBuilder sb = new StringBuilder(); + sb.append("DROP ALL;\n"); + sb.append("PREFIX dc: <http://purl.org/dc/elements/1.1/>\n"); + sb.append("INSERT DATA {\n"); + sb.append(" <http://example/book1> dc:title \"Another new book\" ;\n"); + sb.append(" dc:creator \"A.N.Other\" .\n"); + sb.append("}\n"); + + final String updateStr = sb.toString(); + + final HAGlue leader = quorum.getClient().getLeader(token); + + // Verify quorum is still valid. + quorum.assertQuorum(token); + + getRemoteRepository(leader).prepareUpdate(updateStr).evaluate(); + + // and a second one? + // getRemoteRepository(leader).prepareUpdate(updateStr).evaluate(); + + } + log.warn("CHECK LOGS ON A B"); + + // now shutdown A (not destroy) + shutdownA(); + + // copy log files from A to C + final File serviceDir = new File("benchmark/CI-HAJournal-1"); + copyFiles(new File(serviceDir, "A/HALog"), new File(serviceDir, "C/HALog")); + + startC(); + + log.warn("CHECK LOGS HAVE BEEN COPIED TO C"); + + // new C should Restore and Meet as Follower with B as leader + this.awaitMetQuorum(); + + startA(); + + // A should join the Met Quorum which will then be Fully Met + this.awaitFullyMetQuorum(); + +} + + + /** * Test quorum remains if C is failed when fully met * @throws Exception */ @@ -1207,8 +1347,14 @@ assertHALogNotFound(0L/* firstCommitCounter */, lastCommitCounter, new HAGlue[] { serverA, serverB, serverC }); - // Now fail C - destroyC(); + // Now fail C - use destroy otherwise test does not tear down cleanly + // leaving journal and log files + destroyC(); + + // assert quorum remains met + assertTrue(quorum.isQuorumMet()); + // but not FULLY + assertFalse(quorum.isQuorumFullyMet(token)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-02-22 19:26:49
|
Revision: 6927 http://bigdata.svn.sourceforge.net/bigdata/?rev=6927&view=rev Author: thompsonbry Date: 2013-02-22 19:26:37 +0000 (Fri, 22 Feb 2013) Log Message: ----------- Committing back some small changes. 1. quorumBreak() in HAJournalServer no longer forces a serviceLeave(). This should be automatic (generated by the AbstractQuourm). If there is a reason why we need to do this in quourmBreak, I would like to have that documented and talk it through. 2. Removed the removeAllLogs() methods from HALogManager. The HAJournalServer handles the purge of the HALog files and does so in a manner that is aware of the integration with the HA backup utility. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java 2013-02-22 16:15:50 UTC (rev 6926) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/althalog/HALogManager.java 2013-02-22 19:26:37 UTC (rev 6927) @@ -227,46 +227,50 @@ m_currentLock.unlock(); } } - - /** - * Disables any current log file, then removes all log files - * from the directory - * - * @throws IOException - */ - public void removeAllLogFiles() { - m_currentLock.lock(); - try { - // No longer disables the current log file - - removeAllLogFiles(m_halogdir, getCurrentFile()); - } finally { - m_currentLock.unlock(); - } - } - /** - * Recursively removes all log files from the provided directory - * @param dir + /* + * This logic is handled by the HAJournalServer, which is also aware + * of the backup integration through zookeeper. */ - private void removeAllLogFiles(final File dir, final File preserve) { - final File[] files = logFiles(dir); - for (File f : files) { - try { - if (f.isDirectory()) { - removeAllLogFiles(f, preserve); - - // FIXME: should we remove the directory? - // Probably not - // f.delete(); - } else if (f != preserve) { - f.delete(); - } - } catch (final SecurityException se) { - haLog.warn("Unabel to delete file " + f.getAbsolutePath(), se); - } - } - } +// /** +// * Disables any current log file, then removes all log files +// * from the directory +// * +// * @throws IOException +// */ +// public void removeAllLogFiles() { +// m_currentLock.lock(); +// try { +// // No longer disables the current log file +// +// removeAllLogFiles(m_halogdir, getCurrentFile()); +// } finally { +// m_currentLock.unlock(); +// } +// } +// +// /** +// * Recursively removes all log files from the provided directory +// * @param dir +// */ +// private void removeAllLogFiles(final File dir, final File preserve) { +// final File[] files = logFiles(dir); +// for (File f : files) { +// try { +// if (f.isDirectory()) { +// removeAllLogFiles(f, preserve); +// +// // FIXME: should we remove the directory? +// // Probably not +// // f.delete(); +// } else if (f != preserve) { +// f.delete(); +// } +// } catch (final SecurityException se) { +// haLog.warn("Unabel to delete file " + f.getAbsolutePath(), se); +// } +// } +// } /** * Utility program will dump log files (or directories containing log files) Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-22 16:15:50 UTC (rev 6926) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-02-22 19:26:37 UTC (rev 6927) @@ -1033,7 +1033,13 @@ private class QuorumBreakTask implements Callable<Void> { public Void call() throws Exception { - getQuorum().getActor().serviceLeave(); + /* + * Note: I have removed this line. It arrived without + * documentation and I can not find any reason why we should + * have to do a service leave here. The quorum will + * automatically issue service leaves. + */ +// getQuorum().getActor().serviceLeave(); journal.setQuorumToken(Quorum.NO_QUORUM); try { @@ -1276,7 +1282,6 @@ * necessary state in the file system if they were put there by * the leader. */ - if(true) while (true) { long commitCounter = journal.getRootBlockView() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mar...@us...> - 2013-02-26 18:09:41
|
Revision: 6930 http://bigdata.svn.sourceforge.net/bigdata/?rev=6930&view=rev Author: martyncutcher Date: 2013-02-26 18:09:32 +0000 (Tue, 26 Feb 2013) Log Message: ----------- Commit new HA tests and fix problem with commitTimeConsensus for specific service where it had not voted for the consensus Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-02-26 13:04:10 UTC (rev 6929) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-02-26 18:09:32 UTC (rev 6930) @@ -843,18 +843,26 @@ * <code>null</code> if the service is not participating in a * consensus. */ - private Long getLastCommitTimeConsensus(final UUID serviceId) { + private Long getCastVoteIfConsensus(final UUID serviceId) { + lock.lock(); + try { final Iterator<Map.Entry<Long, LinkedHashSet<UUID>>> itr = votes .entrySet().iterator(); while (itr.hasNext()) { final Map.Entry<Long, LinkedHashSet<UUID>> entry = itr.next(); final Set<UUID> votes = entry.getValue(); if (votes.contains(serviceId)) { - return entry.getKey().longValue(); + if (isQuorum(votes.size())) + return entry.getKey().longValue(); + else + return null; } } // Service is not part of a consensus. return null; + } finally { + lock.unlock(); + } } // /** @@ -1620,7 +1628,7 @@ /* * Discover the lastCommitTime of the consensus. */ - final Long lastCommitTime = getLastCommitTimeConsensus(serviceId); + final Long lastCommitTime = getCastVoteIfConsensus(serviceId); if (lastCommitTime == null) { /* * Either the service did not vote for the consensus or there is @@ -2816,11 +2824,14 @@ final UUID clientId = client.getServiceId(); // The current consensus -or- null if our client is not in a // consensus. - final Long lastCommitTime = getLastCommitTimeConsensus(clientId); + final Long lastCommitTime = getCastVoteIfConsensus(clientId); if (lastCommitTime != null) { /* * Our client is in the consensus. */ + if (log.isInfoEnabled()) + log.info("This client is in consensus on commitTime: " + lastCommitTime); + // Get the vote order. This is also the target join // order. final UUID[] voteOrder = votes.get(lastCommitTime) Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java 2013-02-26 13:04:10 UTC (rev 6929) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java 2013-02-26 18:09:32 UTC (rev 6930) @@ -479,6 +479,22 @@ serviceListenerC = null; } + protected void shutdown(final HAGlue service) throws IOException { + if (service == null) { + throw new IllegalArgumentException(); + } + + if (service.equals(serverA)) { + shutdownA(); + } else if (service.equals(serverB)) { + shutdownB(); + } else if (service.equals(serverC)) { + shutdownC(); + } else { + throw new IllegalArgumentException("Unable to match service: " + service); + } + } + private void safeShutdown(final HAGlue haGlue, final ServiceListener serviceListener) { safeShutdown(haGlue, serviceListener, false); // not shutdownNow by default Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-02-26 13:04:10 UTC (rev 6929) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-02-26 18:09:32 UTC (rev 6930) @@ -37,12 +37,14 @@ import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import com.bigdata.ha.HAGlue; import com.bigdata.ha.halog.HALogWriter; import com.bigdata.ha.msg.HARootBlockRequest; import com.bigdata.journal.jini.ha.HAJournalServer.AdministrableHAGlueService; +import com.bigdata.quorum.AsynchronousQuorumCloseException; import com.bigdata.quorum.Quorum; import com.bigdata.rdf.sail.webapp.client.RemoteRepository; @@ -257,11 +259,13 @@ // Verify quorum is FULLY met. final long token = awaitFullyMetQuorum(); - // Verify KB exists. - awaitKBExists(serverA); + // Verify KB exists on leader. + final HAGlue leader = quorum.getClient().getLeader(token); + + awaitKBExists(leader); // Current commit point. - final long lastCommitCounter = serverA + final long lastCommitCounter = leader .getRootBlock(new HARootBlockRequest(null/* storeUUID */)) .getRootBlock().getCommitCounter(); @@ -460,36 +464,6 @@ } /** - * Tests that halog files are generated and identical, and that - * when a server is shutdown its logs remain - */ - public void testStartAB_halog() { - fail("write test"); - } - - /** - * Tests that halog files are generated and identical and then - * removed following resync and fullymet quorum - */ - public void testStartAB_C_halog() { - fail("write test"); - } - - /** - * Tests that halog files are generated and removed after each commit - */ - public void testStartABC_halog() { - fail("write test"); - } - - /** - * Tests that halog files are removed after fully met on rebuild - */ - public void testStartABC_rebuild_halog() { - fail("write test"); - } - - /** * Test Resync of late starting C service * @throws Exception */ @@ -1126,15 +1100,87 @@ } } } - /** - * Test Rebuild of early starting C service where service from previously fully met quorum is not - * started. + + /** + * Test Rebuild of early starting C service where quorum was previously + * fully met. This forces a pipeline re-organisation + * + * @throws Exception */ - public void testStartABC_Rebuild() { - fail("write test"); + public void testStartABC_RebuildWithPipelineReorganisation() throws Exception { + startA(); + startB(); + startC(); + + awaitFullyMetQuorum(); + + // Now run several transactions + for (int i = 0; i < 5; i++) + simpleTransaction(); + + // shutdown AB and destroy C + destroyC(); + shutdownA(); + shutdownB(); + + // Now restart A, B & C + final HAGlue serverC = startC(); + // Ensure that C starts first + Thread.sleep(1000); + + final HAGlue serverA = startA(); + final HAGlue serverB = startB(); + + // A & B should meet [FIXME: starting C early causes this to timeout] + awaitMetQuorum(); + + // C will have go through Rebuild before joining + awaitFullyMetQuorum(); + + // Verify binary equality of ALL journals. + assertDigestsEquals(new HAGlue[] { serverA, serverB, serverC }); } /** + * Test Rebuild of C service where quorum was previously + * fully met and where a new quorum is met before C joins for rebuild. + * + * @throws Exception + */ + public void testStartABC_Rebuild() throws Exception { + startA(); + startB(); + startC(); + + awaitFullyMetQuorum(); + + // Now run several transactions + for (int i = 0; i < 5; i++) + simpleTransaction(); + + // shutdown AB and destroy C + destroyC(); + shutdownA(); + shutdownB(); + + // Now restart A, B & C + + final HAGlue serverA = startA(); + final HAGlue serverB = startB(); + + // A & B should meet [FIXME: starting C early causes this to timeout] + awaitMetQuorum(); + + final HAGlue serverC = startC(); + + // C will have go through Rebuild before joining + awaitFullyMetQuorum(); + + // Verify binary equality of ALL journals. + assertDigestsEquals(new HAGlue[] { serverA, serverB, serverC }); + } + + /** * Test Restore by: * starting ABC * drop C @@ -1159,7 +1205,8 @@ final long token = quorum.awaitQuorum(awaitQuorumTimeout, TimeUnit.MILLISECONDS); - // Verify KB exists. + // Verify KB exists.es miserables oscar 2013 + awaitKBExists(serverA); @@ -1189,7 +1236,8 @@ } // now shutdown C (not destroy) - shutdownC(); + shutdown(serverC); + // shutdownC(); log.warn("CHECK OPEN LOGS ON A B"); @@ -1360,9 +1408,255 @@ /** * Test quorum breaks and reforms when original leader fails + * + * @throws Exception */ - public void testQuorumBreaksABC_failA() { - fail("write test"); + public void testQuorumBreaksABC_failLeader() throws Exception { + + // Start 3 services + final HAGlue serverA = startA(); + final HAGlue serverB = startB(); + final HAGlue serverC = startC(); + + // Wait for a quorum meet. + final long token = quorum.awaitQuorum(awaitQuorumTimeout, + TimeUnit.MILLISECONDS); + + // Verify KB exists. + awaitKBExists(serverA); + + // Now fail leader! + final HAGlue leader = quorum.getClient().getLeader(token); + + shutdown(leader); + + // Now check that quorum meets + + final long token2 = awaitMetQuorum(); + + // with new token + assertTrue(token != token2); + + // and new leader + assertFalse(leader.equals(quorum.getClient().getLeader(token2))); } + + /** + * Tests that halog files are generated and identical, and that + * when a server is shutdown its logs remain + * @throws Exception + */ + public void testStartAB_halog() throws Exception { + // Start 2 services + startA(); + startB(); + + // Run through transaction + simpleTransaction(); + + // close both services + shutdownA(); + shutdownB(); + + // check that logfiles exist + final File serviceDir = new File("benchmark/CI-HAJournal-1"); + final File logsA = new File(serviceDir, "A/HALog"); + final File logsB = new File(serviceDir, "B/HALog"); + + assertTrue(logsA.listFiles().length == 2); + assertTrue(logsB.listFiles().length == 2); + + // Test ends here!! + + // but we'll restart to help teardown + try { + startA(); + startB(); + + awaitMetQuorum(); + } catch (Throwable t) { + log.error("Problem on tidy up", t); + } + } + + /** + * Tests that halog files are generated and identical and then + * removed following resync and fullymet quorum + * + * @throws Exception + */ + public void testStartAB_C_halog() throws Exception { + // Start 2 services + startA(); + startB(); + + // Run through transaction + simpleTransaction(); + + // check that logfiles exist + final File serviceDir = new File("benchmark/CI-HAJournal-1"); + final File logsA = new File(serviceDir, "A/HALog"); + final File logsB = new File(serviceDir, "B/HALog"); + + // There should be 3 halog files from 2 commit points and newly open + assertTrue(logsA.listFiles().length == 3); + assertTrue(logsB.listFiles().length == 3); + + // now just restart to help teardown + startC(); + + awaitFullyMetQuorum(); + + // Run through another transaction + simpleTransaction(); + // all committed logs should be removed with only open log remaining + final File logsC = new File(serviceDir, "C/HALog"); + assertTrue(logsA.listFiles().length == 1); + assertTrue(logsB.listFiles().length == 1); + assertTrue(logsC.listFiles().length == 1); } + + /** + * Tests that halog files are generated and removed after each commit + * once fully met. + * + * Note that committed log files are not purged on FullyMet, only after first + * FullyMet commit. + * + * @throws Exception + */ + public void testStartABC_halog() throws Exception { + // Start 3 services + startA(); + startB(); + startC(); + + awaitFullyMetQuorum(); + + // setup log directories + final File serviceDir = new File("benchmark/CI-HAJournal-1"); + final File logsA = new File(serviceDir, "A/HALog"); + final File logsB = new File(serviceDir, "B/HALog"); + final File logsC = new File(serviceDir, "C/HALog"); + + // committed log files not purged prior to fully met commit + assertLogCount(logsA, 2); + assertLogCount(logsB, 2); + assertLogCount(logsC, 2); + + // Run through transaction + simpleTransaction(); + + // again check that only open log files remaining + assertLogCount(logsA, 1); + assertLogCount(logsB, 1); + assertLogCount(logsC, 1); + + // Now run several transactions + for (int i = 0; i < 5; i++) + simpleTransaction(); + + // again check that only open log files remaining + assertLogCount(logsA, 1); + assertLogCount(logsB, 1); + assertLogCount(logsC, 1); + } + + private void assertLogCount(final File logdir, final int count) { + final int actual = logdir.listFiles().length; + if (actual != count) { + fail("Actual log files: " + actual + ", expected: " + count); + } + } + + /** + * Tests that halog files are removed after fully met on rebuild + * face + * @throws Exception + */ + public void testStartABC_rebuild_halog() throws Exception { + // setup log directories + final File serviceDir = new File("benchmark/CI-HAJournal-1"); + final File logsA = new File(serviceDir, "A/HALog"); + final File logsB = new File(serviceDir, "B/HALog"); + final File logsC = new File(serviceDir, "C/HALog"); + + // Start 3 services + startA(); + startB(); + startC(); + + awaitFullyMetQuorum(); + + // Now run several transactions + for (int i = 0; i < 5; i++) + simpleTransaction(); + + // Now destroy service C + destroyC(); + + // Now run several more transactions on AB + for (int i = 0; i < 5; i++) + simpleTransaction(); + + // 5 committed files + 1 open == 6 + assertLogCount(logsA, 6); + assertLogCount(logsB, 6); + + // and restart C with empty journal, forces Rebuild + startC(); + + awaitFullyMetQuorum(); + + assertLogCount(logsA, 6); + assertLogCount(logsB, 6); + // Log count on C is 1 after quiescent rebuild + assertLogCount(logsC, 1); + + log.warn("CHECK: Committed log files not copied on Rebuild"); + + // Now run several transactions + for (int i = 0; i < 5; i++) + simpleTransaction(); + + // and check that only open log files remaining + assertLogCount(logsA, 1); + assertLogCount(logsB, 1); + assertLogCount(logsC, 1); + + } + + + /** + * Commits update transaction after awaiting quorum + */ + private void simpleTransaction() throws IOException, Exception { + final long token = quorum.awaitQuorum(awaitQuorumTimeout, + TimeUnit.MILLISECONDS); + + /* + * Now go through a commit point with a fully met quorum. The HALog + * files should be purged at that commit point. + */ + + final StringBuilder sb = new StringBuilder(); + sb.append("DROP ALL;\n"); + sb.append("PREFIX dc: <http://purl.org/dc/elements/1.1/>\n"); + sb.append("INSERT DATA {\n"); + sb.append(" <http://example/book1> dc:title \"A new book\" ;\n"); + sb.append(" dc:creator \"A.N.Other\" .\n"); + sb.append("}\n"); + + final String updateStr = sb.toString(); + + final HAGlue leader = quorum.getClient().getLeader(token); + + // Verify quorum is still valid. + quorum.assertQuorum(token); + + getRemoteRepository(leader).prepareUpdate(updateStr).evaluate(); + + } + +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-01 20:50:29
|
Revision: 6944 http://bigdata.svn.sourceforge.net/bigdata/?rev=6944&view=rev Author: thompsonbry Date: 2013-03-01 20:50:22 +0000 (Fri, 01 Mar 2013) Log Message: ----------- Included the serviceId in the ZK BOUNCE messages. Made getServiceID() final. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-01 18:25:46 UTC (rev 6943) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-01 20:50:22 UTC (rev 6944) @@ -5212,7 +5212,7 @@ private final AtomicBoolean vote = new AtomicBoolean(false); @Override - public UUID getServiceId() { + final public UUID getServiceId() { return serviceId; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-03-01 18:25:46 UTC (rev 6943) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-03-01 20:50:22 UTC (rev 6944) @@ -1255,9 +1255,13 @@ if (getQuorum() instanceof ZKQuorumImpl) { + // Note: Local method call on AbstractJournal. + final UUID serviceId = getServiceId(); + try { - haLog.warn("BOUNCING ZOOKEEPER CONNECTION."); + haLog.warn("BOUNCING ZOOKEEPER CONNECTION: " + + serviceId); // Close the current connection (if any). ((ZKQuorumImpl) getQuorum()).getZookeeper().close(); @@ -1265,7 +1269,7 @@ // Obtain a new connection. ((ZKQuorumImpl) getQuorum()).getZookeeper(); - haLog.warn("RECONNECTED TO ZOOKEEPER."); + haLog.warn("RECONNECTED TO ZOOKEEPER: " + serviceId); } catch (InterruptedException e) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-07 15:36:52
|
Revision: 6969 http://bigdata.svn.sourceforge.net/bigdata/?rev=6969&view=rev Author: thompsonbry Date: 2013-03-07 15:36:43 +0000 (Thu, 07 Mar 2013) Log Message: ----------- Added method to report the pid of the HAJournalServer process out through the NSS status page. Added javadoc concerning testStartABCSimultaneous() deadlock. We now have stack traces that show what is going on here. The problem is that the 3rd service is awaiting the set of the quourm token and installation of the root blocks from the leader while the leader is waiting on WriteCacheService.flush() which is waiting on the 3rd service to setup the pipeline (and hence waiting for the quorum token and root block install). Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-03-07 14:21:00 UTC (rev 6968) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-03-07 15:36:43 UTC (rev 6969) @@ -84,6 +84,11 @@ * Return the directory in which we are logging the write blocks. */ File getHALogDir(); + + /** + * Return the best guess at the process identifier for this process. + */ + int getPID(); /** * Return the configured timeout in milliseconds that the leader will await Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-03-07 14:21:00 UTC (rev 6968) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-03-07 15:36:43 UTC (rev 6969) @@ -475,6 +475,12 @@ public File getServiceDir() { throw new UnsupportedOperationException(); } + + @Override + public int getPID() { + throw new UnsupportedOperationException(); + } + }; } Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-03-07 14:21:00 UTC (rev 6968) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-03-07 15:36:43 UTC (rev 6969) @@ -220,7 +220,15 @@ private File serviceIdFile; /** + * The PID (best guess). + * + * @see PIDUtil#getPID() + */ + private final int pid; + + /** * The file on which the PID was written. + * @see #writePIDFile(File) */ private File pidFile; @@ -356,6 +364,15 @@ } /** + * The best guess at the process identifier for this process. + */ + final protected int getPID() { + + return pid; + + } + + /** * <code>true</code> iff this is a persistent service (one that you can * shutdown and restart). */ @@ -573,6 +590,9 @@ // } // }); + // Note the process id (best guess). + this.pid = PIDUtil.getPID(); + /* * Read jini configuration & service properties */ @@ -1121,7 +1141,7 @@ try { // best guess at the PID of the JVM. - final String pid = Integer.toString(PIDUtil.getPID()); + final String pidStr = Integer.toString(this.pid); // open the file. final FileOutputStream os = new FileOutputStream(file); @@ -1132,7 +1152,7 @@ os.getChannel().truncate(0L); // write on the PID using ASCII characters. - os.write(pid.getBytes("ASCII")); + os.write(pidStr.getBytes("ASCII")); // flush buffers. os.flush(); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-07 14:21:00 UTC (rev 6968) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-07 15:36:43 UTC (rev 6969) @@ -962,6 +962,13 @@ } + @Override + public int getPID() { + + return server.getPID(); + + } + /** * Resolve an {@link HAGlue} object from its Service UUID. */ @@ -2912,6 +2919,14 @@ * use any high latency or RMI calls unless we need to wait for the * root blocks. That condition is detected below without any high * latency operations. + * + * FIXME A deadlock has been observed when the leader is attempting + * to commit the initial KB create, the 3rd service is attempting + * to synchronize with the met quorum (and is in this code block) + * and client is attempting to discover whether or not the KB has + * been created (awaitKBCreate()). + * + * @see TestHA3JournalServer#testABCStartSimultaneous */ S leader = null; IRootBlockView rbLeader = null; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-10 16:53:28
|
Revision: 6974 http://bigdata.svn.sourceforge.net/bigdata/?rev=6974&view=rev Author: thompsonbry Date: 2013-03-10 16:53:18 +0000 (Sun, 10 Mar 2013) Log Message: ----------- Modified the IHAWriteMessage to include the UUID of the store on which the write was applied by the leader. This is used in handleReplicatedWrite() to avoid invoking pipelineSetup() for a live write before the local root blocks are consistent with those of the leader. This change was introduced to address a deadlock problem in CI for the ABC "Simultaneous" start test. Note: It was a bit messy to get the storeUUID into the RWStore due to the multiplicity of code paths in the handling of RWStore initialization in the ctor and in initFromRootBlock(). There was an undetected problem where the JournalMetadata was immutable, but in HA we can now replace the storeUUID with the UUID from the leader. I updated the relevant code paths in AbstractJournal to handle this case (getUUID(), etc). I have updated the HAJournalServer CI test worksheet. All looks good. I have run the various WCS, HA, Journal and SPARQL level test suites locally. All looks good there too. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipelineImpl.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HAWriteMessage.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHAWriteMessage.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/althalog/TestAltHALogWriter.java branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/halog/TestHALogWriter.java branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/msg/TestHAWriteMessage.java branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -29,6 +29,7 @@ import java.io.IOException; import java.nio.ByteBuffer; +import java.util.UUID; import java.util.concurrent.Future; import com.bigdata.ha.halog.HALogWriter; @@ -137,6 +138,11 @@ long getLastCommitCounter(); /** + * The {@link UUID} of the backing store. + */ + UUID getStoreUUID(); + + /** * Log the {@link IHAWriteMessage} and the associated data (if necessary). * The log file for the current write set will be deleted if the quorum is * fully met at the next 2-phase commit. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipelineImpl.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipelineImpl.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipelineImpl.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -160,6 +160,24 @@ .getLogger(QuorumPipelineImpl.class); /** + * The timeouts for a sleep before the next retry. These timeouts are + * designed to allow some asynchronous processes to reconnect the + * {@link HASendService} and the {@link HAReceiveService}s in write pipeline + * such that a retransmit can succeed after a service has left the pipeline. + * Depending on the nature of the error (i.e., a transient network problem + * versus a pipeline reorganization), this can involve a number of zookeeper + * events. Hence the sleep latency is backed off through this array of + * values. + * + * TODO We do not want to induce too much latency here. It would be nice if + * we automatically retried after each relevant quorum event that might cure + * the problem as well as after a timeout. This would require a Condition + * that we await with a timeout and signaling the Condition if there are any + * relevant events (probably once we handle them locally). + */ + static protected final int RETRY_SLEEP[] = new int[] { 100, 200, 200, 500, 500, 1000 }; + + /** * The {@link QuorumMember}. */ protected final QuorumMember<S> member; @@ -772,21 +790,6 @@ */ private final long quorumToken; - /** - * The #of times the leader in a highly available quorum will attempt to - * retransmit the current write cache block if there is an error when - * sending that write cache block to the downstream node. - */ - static protected final int RETRY_COUNT = 3; - - /** - * The timeout for a sleep before the next retry. This timeout is designed - * to allow some asynchronous processes to reconnect the - * {@link HASendService} and the {@link HAReceiveService}s in write pipeline - * such that a retransmit can succeed after a service has left the pipeline. - */ - static protected final int RETRY_SLEEP = 50; - public RobustReplicateTask(final IHASyncRequest req, final IHAWriteMessage msg, final ByteBuffer b) { @@ -860,8 +863,9 @@ // Rethrow the original exception. throw new RuntimeException( - "Giving up. Could not send after " + RETRY_COUNT - + " attempts : " + t, t); + "Giving up. Could not send after " + + RETRY_SLEEP.length + " attempts : " + t, + t); } @@ -957,10 +961,10 @@ int tryCount = 1; // now try some more times. - for (; tryCount < RETRY_COUNT; tryCount++) { + for (; tryCount < RETRY_SLEEP.length; tryCount++) { // Sleep before each retry (including the first). - Thread.sleep(RETRY_SLEEP/* ms */); + Thread.sleep(RETRY_SLEEP[tryCount-1]/* ms */); try { Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumServiceBase.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -112,6 +112,13 @@ } @Override + public UUID getStoreUUID() { + + return QuorumServiceBase.this.getStoreUUID(); + + } + + @Override public long getLastCommitTime() { return QuorumServiceBase.this.getLastCommitTime(); @@ -323,6 +330,15 @@ } @Override + final public UUID getStoreUUID() { + + final L localService = getLocalService(); + + return localService.getRootBlockView().getUUID(); + + } + + @Override final public long getLastCommitTime() { final L localService = getLocalService(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HAWriteMessage.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HAWriteMessage.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/HAWriteMessage.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -30,6 +30,7 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; +import java.util.UUID; import com.bigdata.journal.StoreTypeEnum; @@ -48,6 +49,9 @@ */ private static final long serialVersionUID = -2673171474897401979L; + /** The {@link UUID} of the store to which this message belongs. */ + private UUID uuid; + /** The most recent commit counter associated with this message */ private long commitCounter; @@ -69,6 +73,11 @@ /** The file offset at which the data will be written (WORM only). */ private long firstOffset; + @Override + public UUID getUUID() { + return uuid; + } + /* (non-Javadoc) * @see com.bigdata.journal.ha.IHAWriteMessage#getCommitCounter() */ @@ -130,6 +139,7 @@ return getClass().getName() // + "{size=" + getSize() // + ",chksum=" + getChk() // + + ",uuid="+getUUID() // + ",commitCounter=" + commitCounter // + ",commitTime=" + lastCommitTime // + ",sequence=" + sequence // @@ -148,6 +158,12 @@ } /** + * @param uuid + * The {@link UUID} associated with the backing store on the + * leader. This can be used to decide whether the message is for + * a given store, or (conversly) whether the receiver has already + * setup its root blocks based on the leader (and hence has the + * correct {@link UUID} for its local store). * @param commitCounter * The commit counter for the current root block for the write * set which is being replicated by this message. @@ -171,16 +187,22 @@ * @param firstOffset * The file offset at which the data will be written (WORM only). */ - public HAWriteMessage(final long commitCounter, final long commitTime, - final long sequence, final int sze, final int chk, - final StoreTypeEnum storeType, final long quorumToken, - final long fileExtent, final long firstOffset) { + public HAWriteMessage(final UUID uuid, final long commitCounter, + final long commitTime, final long sequence, final int sze, + final int chk, final StoreTypeEnum storeType, + final long quorumToken, final long fileExtent, + final long firstOffset) { super(sze, chk); + if (uuid == null) + throw new IllegalArgumentException(); + if (storeType == null) throw new IllegalArgumentException(); + this.uuid = uuid; + this.commitCounter = commitCounter; this.lastCommitTime = commitTime; @@ -197,8 +219,21 @@ } + /** + * The initial version. + */ private static final byte VERSION0 = 0x0; + /** + * Adds the {@link #uuid} field. + */ + private static final byte VERSION1 = 0x1; + + /** + * The current version. + */ + private static final byte currentVersion = VERSION1; + @Override public boolean equals(final Object obj) { @@ -213,7 +248,8 @@ final IHAWriteMessage other = (IHAWriteMessage) obj; - return commitCounter == other.getCommitCounter() + return ((uuid == null && other.getUUID() == null) || uuid.equals(other.getUUID())) + && commitCounter == other.getCommitCounter() && lastCommitTime == other.getLastCommitTime() // && sequence == other.getSequence() && storeType == other.getStoreType() @@ -230,7 +266,14 @@ final byte version = in.readByte(); switch (version) { case VERSION0: + uuid = null; // Note: not available. break; + case VERSION1: + uuid = new UUID(// + in.readLong(), // MSB + in.readLong() // LSB + ); + break; default: throw new IOException("Unknown version: " + version); } @@ -245,7 +288,11 @@ public void writeExternal(final ObjectOutput out) throws IOException { super.writeExternal(out); - out.write(VERSION0); + out.write(currentVersion); + if (currentVersion >= VERSION1) { + out.writeLong(uuid.getMostSignificantBits()); + out.writeLong(uuid.getLeastSignificantBits()); + } out.writeByte(storeType.getType()); out.writeLong(commitCounter); out.writeLong(lastCommitTime); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHAWriteMessage.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHAWriteMessage.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/msg/IHAWriteMessage.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -23,6 +23,8 @@ */ package com.bigdata.ha.msg; +import java.util.UUID; + import com.bigdata.journal.StoreTypeEnum; /** @@ -33,6 +35,9 @@ */ public interface IHAWriteMessage extends IHAWriteMessageBase { + /** The {@link UUID} of the store to which this message belongs. */ + UUID getUUID(); + /** The commit counter associated with this message */ long getCommitCounter(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCache.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListMap; @@ -1532,6 +1533,7 @@ * @return cache A {@link WriteCache} to be replicated. */ final IHAWriteMessage newHAWriteMessage(// + final UUID storeUUID, final long quorumToken, final long lastCommitCounter,// final long lastCommitTime,// @@ -1539,7 +1541,8 @@ final ByteBuffer tmp ) { - return new HAWriteMessage( + return new HAWriteMessage(// + storeUUID,// lastCommitCounter,// lastCommitTime,// sequence, // Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/io/writecache/WriteCacheService.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -1389,7 +1389,9 @@ assert quorumMember != null : "Not quorum member?"; - final IHAWriteMessage msg = cache.newHAWriteMessage(quorumToken,// + final IHAWriteMessage msg = cache.newHAWriteMessage(// + quorumMember.getStoreUUID(),// + quorumToken,// quorumMember.getLastCommitCounter(),// quorumMember.getLastCommitTime(),// thisSequence,// Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -331,10 +331,17 @@ */ private final IBufferStrategy _bufferStrategy; - /** - * A description of the journal as a resource. - */ - private final JournalMetadata journalMetadata; + /** + * A description of the journal as a resource. + * <p> + * Note: For HA, this is updated if new root blocks are installed onto the + * journal. This is necessary since that operation changes the {@link UUID} + * of the backing store, which is one of the things reported by the + * {@link JournalMetadata} class. + * + * @see #installRootBlocks(IRootBlockView, IRootBlockView) + */ + private final AtomicReference<JournalMetadata> journalMetadata = new AtomicReference<JournalMetadata>(); /* * @@ -1237,7 +1244,7 @@ */ // Save resource description (sets value returned by getUUID()). - this.journalMetadata = new JournalMetadata(this); + this.journalMetadata.set(new JournalMetadata(this)); // new or reload from the store root block. this._commitRecord = _getCommitRecord(); @@ -2170,13 +2177,13 @@ final public UUID getUUID() { - return journalMetadata.getUUID(); + return journalMetadata.get().getUUID(); } final public IResourceMetadata getResourceMetadata() { - return journalMetadata; + return journalMetadata.get(); } @@ -4926,7 +4933,7 @@ // This quorum member. final QuorumService<HAGlue> localService = quorum.getClient(); - if (_rootBlock.getCommitCounter() == 0 + if (_rootBlock.getCommitCounter() == 0L && localService.isFollower(quorumToken)) { /* @@ -4945,11 +4952,27 @@ throw new RuntimeException(e); } - // Installs the root blocks and does a local abort. - localService.installRootBlocks( - tmp.asRootBlock(true/* rootBlock0 */), - tmp.asRootBlock(false/* rootBlock0 */)); + if (tmp.getCommitCounter() == 0L) { + /* + * Installs the root blocks and does a local abort. + * + * Note: This code path is only taken when both the + * leader and the follower are at commitCounter==0L. + * This prevents us from accidentally laying down on a + * follower the root blocks corresponding to a leader + * that already has committed write sets. + */ + localService.installRootBlocks( + tmp.asRootBlock(true/* rootBlock0 */), + tmp.asRootBlock(false/* rootBlock0 */)); + } else { + + // Still need to do that local abort. + doLocalAbort(); + + } + } else { // The leader also needs to do a local abort. @@ -5019,6 +5042,12 @@ // final IRootBlockView rootBlock1 = new RootBlockView( // false/* rootBlock0 */, rootBlock0.asReadOnlyBuffer(), checker); + final WriteLock lock = _fieldReadWriteLock.writeLock(); + + lock.lock(); + + try { + // Check the root blocks before we install them. { if (!_rootBlock.getStoreType().equals(rootBlock0.getStoreType())) { @@ -5041,6 +5070,9 @@ // Choose the "current" root block. _rootBlock = RootBlockUtility.chooseRootBlock(rootBlock0, rootBlock1); + // Save resource description (sets value returned by getUUID()). + journalMetadata.set(new JournalMetadata(this)); + haLog.warn("Installed new root blocks: rootBlock0=" + rootBlock0 + ", rootBlock1=" + rootBlock1); @@ -5069,6 +5101,12 @@ */ doLocalAbort(); + + } finally { + + lock.unlock(); + + } } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/WORMStrategy.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -23,19 +23,14 @@ */ package com.bigdata.journal; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.EOFException; import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.FileChannel; import java.security.DigestException; import java.security.MessageDigest; -import java.util.ArrayList; import java.util.Map; import java.util.UUID; import java.util.concurrent.Future; @@ -68,8 +63,6 @@ import com.bigdata.io.writecache.WriteCacheCounters; import com.bigdata.io.writecache.WriteCacheService; import com.bigdata.quorum.Quorum; -import com.bigdata.rawstore.IAllocationContext; -import com.bigdata.rawstore.IPSOutputStream; import com.bigdata.rawstore.IRawStore; import com.bigdata.util.ChecksumError; import com.bigdata.util.ChecksumUtility; @@ -2559,9 +2552,9 @@ final int chk = ChecksumUtility.threadChk.get().checksum(b); - final IHAWriteMessage msg = new HAWriteMessage(-1L/* commitCounter */, - -1L/* commitTime */, sequence, nbytes, chk, StoreTypeEnum.WORM, - quorumToken, fileExtent, offset/* firstOffset */); + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, + -1L/* commitCounter */, -1L/* commitTime */, sequence, nbytes, + chk, StoreTypeEnum.WORM, quorumToken, fileExtent, offset/* firstOffset */); final Future<Void> remoteWriteFuture = quorumMember.replicate(req, msg, clientBuffer); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -44,6 +44,7 @@ import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; +import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; @@ -413,6 +414,14 @@ // private boolean m_readOnly; /** + * The UUID of the backing store. + * + * @see #initfromRootBlock(IRootBlockView) + * @see IRawStore#getUUID() + */ + private UUID m_storeUUID; + + /** * lists of total alloc blocks. * * @todo examine concurrency and lock usage for {@link #m_alloc} and the @@ -785,7 +794,14 @@ try { if (m_rb.getNextOffset() == 0) { // if zero then new file setAllocations(fileMetadata); - + + /* + * FIXME Martyn, the code paths here are crazy complicated. + * defaultInit() is also invoked from initFromRootBlock(). + * Simplify this. BBT + */ + m_storeUUID = m_rb.getUUID(); + defaultInit(); m_maxFixedAlloc = m_allocSizes[m_allocSizes.length-1]*64; @@ -1128,6 +1144,8 @@ // m_rb = m_fmv.getRootBlock(); assert(m_rb != null); + m_storeUUID = m_rb.getUUID(); + if (m_rb.getNextOffset() == 0) { defaultInit(); @@ -5321,9 +5339,9 @@ final int chk = ChecksumUtility.threadChk.get().checksum(b); - final IHAWriteMessage msg = new HAWriteMessage(-1L/* commitCounter */, - -1L/* commitTime */, sequence, nbytes, chk, StoreTypeEnum.RW, - quorumToken, fileExtent, offset/* firstOffset */); + final IHAWriteMessage msg = new HAWriteMessage(m_storeUUID, + -1L/* commitCounter */, -1L/* commitTime */, sequence, nbytes, + chk, StoreTypeEnum.RW, quorumToken, fileExtent, offset/* firstOffset */); final Future<Void> remoteWriteFuture = quorumMember.replicate(req, msg, clientBuffer); Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/althalog/TestAltHALogWriter.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/althalog/TestAltHALogWriter.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/althalog/TestAltHALogWriter.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -145,7 +145,9 @@ final ByteBuffer data = randomData(2000); - IHAWriteMessage msg = new HAWriteMessage(rbv.getCommitCounter(), rbv + final UUID storeUUID = UUID.randomUUID(); + + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv.getCommitCounter(), rbv .getFirstCommitTime(), sequence, data.limit(), checker .checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); @@ -183,7 +185,9 @@ final ByteBuffer data = randomData(2000); - IHAWriteMessage msg = new HAWriteMessage(rbv.getCommitCounter(), rbv + final UUID storeUUID = UUID.randomUUID(); + + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv.getCommitCounter(), rbv .getFirstCommitTime(), sequence, data.limit(), checker .checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); @@ -235,7 +239,9 @@ final ByteBuffer data = randomData(2000); - IHAWriteMessage msg = new HAWriteMessage(rbv.getCommitCounter(), rbv + final UUID storeUUID = UUID.randomUUID(); + + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv.getCommitCounter(), rbv .getFirstCommitTime(), sequence, data.limit(), checker .checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); @@ -246,7 +252,8 @@ manager.disable(); try { - IHAWriteMessage msg2 = new HAWriteMessage(rbv.getCommitCounter(), rbv + + final IHAWriteMessage msg2 = new HAWriteMessage(storeUUID, rbv.getCommitCounter(), rbv .getFirstCommitTime(), sequence+1, data.limit(), checker .checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); @@ -285,13 +292,14 @@ @Override public void run() { + final UUID storeUUID = UUID.randomUUID(); try { for (int i = 0; i < count; i++) { // add delay to write thread to test read thread waiting for // data Thread.sleep(1); data.limit(200 + r.nextInt(1800)); - IHAWriteMessage msg = new HAWriteMessage(rbv + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv .getCommitCounter(), rbv.getLastCommitTime(), sequence++, data.limit(), checker.checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/halog/TestHALogWriter.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/halog/TestHALogWriter.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/halog/TestHALogWriter.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -114,7 +114,9 @@ final ByteBuffer data = randomData(2000); - IHAWriteMessage msg = new HAWriteMessage(rbv.getCommitCounter(), rbv + final UUID storeUUID = UUID.randomUUID(); + + IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv.getCommitCounter(), rbv .getFirstCommitTime(), sequence, data.limit(), checker .checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); @@ -153,7 +155,9 @@ final ByteBuffer data = randomData(2000); - IHAWriteMessage msg = new HAWriteMessage(rbv.getCommitCounter(), rbv + final UUID storeUUID = UUID.randomUUID(); + + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv.getCommitCounter(), rbv .getFirstCommitTime(), sequence, data.limit(), checker .checksum(data), rbv.getStoreType(), rbv.getQuorumToken(), 1000, 0); @@ -206,11 +210,12 @@ @Override public void run() { + final UUID storeUUID = UUID.randomUUID(); try { for (int i = 0; i < count; i++) { // add delay to write thread to test read thread waiting for data Thread.sleep(10); - IHAWriteMessage msg = new HAWriteMessage(rbv + final IHAWriteMessage msg = new HAWriteMessage(storeUUID, rbv .getCommitCounter(), rbv.getLastCommitTime(), sequence++, data.limit(), checker .checksum(data), rbv.getStoreType(), Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/msg/TestHAWriteMessage.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/msg/TestHAWriteMessage.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/ha/msg/TestHAWriteMessage.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -24,6 +24,7 @@ package com.bigdata.ha.msg; import java.io.IOException; +import java.util.UUID; import junit.framework.TestCase; @@ -39,6 +40,7 @@ public void testSerialization() throws IOException, ClassNotFoundException { final IHAWriteMessage msg1 = new HAWriteMessage( + UUID.randomUUID(),// store UUID 12L,// commitCounter 13L,// commitTime 14L,// sequence Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestRWWriteCacheService.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -48,6 +48,7 @@ import com.bigdata.quorum.QuorumActor; import com.bigdata.rwstore.RWWriteCacheService; import com.bigdata.util.ChecksumUtility; +import com.bigdata.util.InnerCause; /** * Test suite for the {@link WriteCacheService} using scattered writes on a @@ -334,6 +335,14 @@ writeCache.write(v.addr, v.buf.asReadOnlyBuffer(), checker .checksum(v.buf)); } catch (Throwable t) { + /** + * FIXME This test is broken both here and at the following + * flush(). + * + * @see https://sourceforge.net/apps/trac/bigdata/ticket/651 + * (RWS test failure) + */ +// if(!InnerCause.isInnerCause(t, AssertionError.class)) { if (!(t instanceof AssertionError)) { fail("Expecting " + AssertionError.class.getName() + ", not " + t, t); Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/io/writecache/TestWORMWriteCacheService.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -341,6 +341,11 @@ } @Override + public UUID getStoreUUID() { + return MyMockQuorumMember.this.getStoreUUID(); + } + + @Override public long getLastCommitTime() { return MyMockQuorumMember.this.getLastCommitTime(); @@ -435,6 +440,13 @@ } @Override + public UUID getStoreUUID() { + + return storeUUID; + + } + + @Override public long getLastCommitTime() { return lastCommitTime; @@ -448,6 +460,7 @@ } + private UUID storeUUID = UUID.randomUUID(); private long lastCommitCounter = 0; private long lastCommitTime = 0; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -676,6 +676,11 @@ } @Override + public UUID getStoreUUID() { + throw new UnsupportedOperationException(); + } + + @Override public long getLastCommitTime() { // TODO Auto-generated method stub return 0; Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -1559,20 +1559,36 @@ * on the journal and a few other things in place. This does not * exactly correspond to the pre-conditions on RunMet. It is * more like the post-conditions on pipelineSetup(). + * + * Note: We MUST NOT install the local root blocks unless both + * this service and the leader at at commitCounter ZERO(0L). */ + awaitJournalToken(token); { - // The current root block. - final IRootBlockView rb = journal.getRootBlockView(); + /* + * The current root block on the leader (We want to get some + * immutatable metadata from the leader's root block). + */ + final IRootBlockView rb = leader.getRootBlock( + new HARootBlockRequest(null/* storeUUID */)) + .getRootBlock();// journal.getRootBlockView(); // Use timestamp. final long createTime = System.currentTimeMillis(); // New root blocks for a (logically) empty Journal. - final RootBlockUtility rbu = new RootBlockUtility(journal - .getBufferStrategy().getBufferMode(), - rb.getOffsetBits(), createTime, token, rb.getUUID()); + final RootBlockUtility rbu = new RootBlockUtility(// + journal.getBufferStrategy().getBufferMode(), // + rb.getOffsetBits(), // from leader. + createTime, // + token, // + rb.getUUID() // storeUUID from leader. + ); + // Verify that the quorum remains met on this token. + getQuorum().assertQuorum(token); + /* * Install both root blocks. * @@ -1610,6 +1626,9 @@ } + // Verify that the quorum remains met on this token. + getQuorum().assertQuorum(token); + // Caught up on the backing store as of that copy. installRootBlocks(resp.getRootBlock0(), resp.getRootBlock1()); @@ -2234,13 +2253,18 @@ protected void handleReplicatedWrite(final IHASyncRequest req, final IHAWriteMessage msg, final ByteBuffer data) throws Exception { - if (journal.getQuorumToken() == Quorum.NO_QUORUM && req == null) { + if (req == null //&& journal.getQuorumToken() == Quorum.NO_QUORUM + && journal.getRootBlockView().getCommitCounter() == 0L + && (msg.getUUID() != null && !journal.getUUID().equals(msg.getUUID()))) { /* * This is a live write (part of the current write set). - * However, we do not yet have the quorum token yet and hence do - * not even recognize that a quorum is met so there is - * absolutely nothing that we can do with this write at this - * time. + * However, our root blocks have not yet been updated to reflect + * the leader's root blocks. In this case, if we attempt to + * setup the pipeline before the root blocks + * have been installed, then we risk a distributed deadlock + * where the leader can be waiting for this service to handle + * the replicated write in WriteCacheService.flush() as invoked from commitNow() + * during a commit, but this service is waiting on the * * Note: Deadlocks had been observed before this fast path was * added. This occurred when the leader was attempting to commit @@ -2251,6 +2275,11 @@ * discover whether or not the KB has been created. * * @see TestHA3JournalServer#testABCStartSimultaneous +// * +// * FIXME MUST GUARANTEE INSTALL OF ROOT BLOCKS FROM LEADER IN +// * RESYNC IF COMMIT COUNTER IS ZERO and MUST NOT call +// * pipelineSetup() unless we are already in a state where we are +// * ready to handle either a live write or a historical write. */ return; } @@ -2952,11 +2981,15 @@ Thread.sleep(sleepMillis/* ms */); continue; } - if (isFollower(token)) {// if (awaitRootBlocks) { + if (isFollower(token)) {// if (awaitRootBlocks) { final IRootBlockView rbSelf = journal.getRootBlockView(); - if (rbSelf.getCommitCounter() == 0) { + if (rbSelf.getCommitCounter() == 0L) { /* * Only wait if this is an empty Journal. + * + * Note: We MUST NOT install the local root blocks + * unless both this service and the leader at at + * commitCounter ZERO(0L). */ if (leader == null) { /* @@ -2970,6 +3003,10 @@ .getRootBlock(); } if (!rbSelf.getUUID().equals(rbLeader.getUUID())) { + /* + * Wait if the leader's root block has not yet been + * installed. + */ Thread.sleep(sleepMillis/* ms */); continue; } Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -28,23 +28,15 @@ import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.util.LinkedList; -import java.util.List; import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import com.bigdata.ha.HAGlue; import com.bigdata.ha.halog.HALogWriter; import com.bigdata.ha.msg.HARootBlockRequest; -import com.bigdata.journal.jini.ha.HAJournalServer.AdministrableHAGlueService; -import com.bigdata.quorum.AsynchronousQuorumCloseException; import com.bigdata.quorum.Quorum; import com.bigdata.rdf.sail.webapp.client.RemoteRepository; @@ -239,23 +231,10 @@ */ public void testStartABCSimultaneous() throws Exception { - final HAGlue serverA, serverB, serverC; - { - final List<Callable<HAGlue>> tasks = new LinkedList<Callable<HAGlue>>(); - - tasks.add(new StartATask(false/*restart*/)); - tasks.add(new StartBTask(false/*restart*/)); - tasks.add(new StartCTask(false/*restart*/)); + final ABC abc = new ABC(); // simultaneous start. - // Start all servers in parallel. Wait up to a timeout. - final List<Future<HAGlue>> futures = executorService.invokeAll( - tasks, 30/* timeout */, TimeUnit.SECONDS); + final HAGlue serverA = abc.serverA, serverB = abc.serverB, serverC = abc.serverC; - serverA = futures.get(0).get(); - serverB = futures.get(1).get(); - serverC = futures.get(2).get(); - } - // Verify quorum is FULLY met. final long token = awaitFullyMetQuorum(); Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java 2013-03-08 14:33:13 UTC (rev 6973) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestRawTransfers.java 2013-03-10 16:53:18 UTC (rev 6974) @@ -93,10 +93,10 @@ transfer.limit(sze); src.readRaw(position, transfer); - final IHAWriteMessage msg = new HAWriteMessage(-1, -1, - sequence++, sze, -1/*chk*/, - mode.getStoreType(), -1 /*quorumToken*/, - extent, position); + final IHAWriteMessage msg = new HAWriteMessage( + journal1.getUUID(), -1, -1, sequence++, sze, + -1/* chk */, mode.getStoreType(), -1 /* quorumToken */, + extent, position); dst.writeRawBuffer(req, msg, transfer); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-11 15:30:24
|
Revision: 6978 http://bigdata.svn.sourceforge.net/bigdata/?rev=6978&view=rev Author: thompsonbry Date: 2013-03-11 15:30:16 +0000 (Mon, 11 Mar 2013) Log Message: ----------- Fix to AbstractQuorum.watcher.pipelineRemove(). It was failing to use the doAction() mechanism to submit the setToken() action in a different thread, with the result that a deadlock could arise from an action executed within the zk event thread. AbstractJournal.setQuorumToken() simplified logic around the decision for invoking doLocalAbort() versus installRootBlocks. Bug fix to HA3 test suite where test failed to start A,B after a shutdown. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-11 12:49:21 UTC (rev 6977) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-11 15:30:16 UTC (rev 6978) @@ -4937,26 +4937,29 @@ // This quorum member. final QuorumService<HAGlue> localService = quorum.getClient(); + boolean installedRBs = false; + if (_rootBlock.getCommitCounter() == 0L && localService.isFollower(quorumToken)) { /* * Take the root blocks from the quorum leader and use them. */ + // Remote interface for the quorum leader. final HAGlue leader = localService.getLeader(quorumToken); log.info("Fetching root block from leader."); - final IRootBlockView tmp; + final IRootBlockView leaderRB; try { - tmp = leader.getRootBlock( + leaderRB = leader.getRootBlock( new HARootBlockRequest(null/* storeUUID */)) .getRootBlock(); } catch (IOException e) { throw new RuntimeException(e); } - if (tmp.getCommitCounter() == 0L) { + if (leaderRB.getCommitCounter() == 0L) { /* * Installs the root blocks and does a local abort. @@ -4968,22 +4971,30 @@ * that already has committed write sets. */ localService.installRootBlocks( - tmp.asRootBlock(true/* rootBlock0 */), - tmp.asRootBlock(false/* rootBlock0 */)); - } else { - - // Still need to do that local abort. - doLocalAbort(); - + leaderRB.asRootBlock(true/* rootBlock0 */), + leaderRB.asRootBlock(false/* rootBlock0 */)); + + installedRBs = true; + } - } else { + } - // The leader also needs to do a local abort. + if (!installedRBs) { + + /* + * If we install the RBs, the a local abort was already + * done. Otherwise we need to do one now (this covers the + * case when setQuorumToken() is called on the leader as + * well as cases where the service is either not a follower + * or is a follower, but the leader is not at + * commitCounter==0L, etc. + */ + doLocalAbort(); - + } - + } else { throw new AssertionError(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-03-11 12:49:21 UTC (rev 6977) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-03-11 15:30:16 UTC (rev 6978) @@ -1029,28 +1029,33 @@ } final public UUID getLeaderId() { + UUID leaderId = null; + final long tmp; lock.lock(); try { /* - * Note: [token] is VOLATILE so it can change while we are holding + * Note: [token] is VOLATILE, so it can change while we are holding * the lock. Therefore, we have to explicitly guard against this. */ - final long tmp = token(); + tmp = token; // value of token on entry. if (token == NO_QUORUM) { + // No quorum, no leader. return null; } final UUID[] joined = getJoined(); - assertQuorum(tmp); // ensure quorum still met. - if (joined == null) - throw new AssertionError(); - final UUID leaderId = joined[0]; - assertQuorum(tmp); // ensure quorum still met. - if (leaderId == null) - throw new AssertionError(); - return leaderId; + if (joined.length > 0) { + // Set IFF available. + leaderId = joined[0]; + } } finally { lock.unlock(); } + if (token != tmp) { + // token concurrently changed. + return null; + } + // token remained valid, return whatever we have. + return leaderId; } final public long token() { @@ -1881,9 +1886,18 @@ doSetToken(newValue); guard(new Guard() { public void run() throws InterruptedException { +// log.fatal("LOOP: ENTER: newValue=" + newValue +// + ", lastValidToken=" + lastValidToken + ", token=" +// + token, new RuntimeException("THREAD TRACE")); while (lastValidToken == oldValue && client != null) { quorumChange.await(); +// log.fatal("LOOP: AWOKE: newValue=" + newValue +// + ", lastValidToken=" + lastValidToken +// + ", token=" + token); } +// log.fatal("LOOP: EXIT: newValue=" + newValue +// + ", lastValidToken=" + lastValidToken + ", token=" +// + token); } }); if (client == null) @@ -2502,7 +2516,30 @@ log.info("Electing leader: " + AbstractQuorum.this .toString()); - actor.setToken(lastValidToken + 1); + doAction(new Runnable() { + /* + * Note: This needs to be submitted + * as an action since we will + * otherwise be in the zk event + * thread and be unable to observe + * the effect of the action that we + * take. + * + * This was observed for the + * following HA3 test. A was unable + * to observe the new token value + * when it invoked setToken() from + * the current thread rather than by + * submitting the setToken() method + * in a runnable as we do here. + * + * See TestHA3JournalServer. + * testStartABC_RebuildWithPipelineReorganisation + */ + public void run() { + actor.setToken(lastValidToken + 1); + } + }); } } } Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-03-11 12:49:21 UTC (rev 6977) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3JournalServer.java 2013-03-11 15:30:16 UTC (rev 6978) @@ -1074,8 +1074,8 @@ // Now restart A, B & C final HAGlue serverC = startC(); - // Ensure that C starts first - Thread.sleep(100); + // Ensure that C gets into the pipeline before we start A/B. + Thread.sleep(1000); final HAGlue serverA = startA(); final HAGlue serverB = startB(); @@ -1634,11 +1634,9 @@ shutdownB(); shutdownC(); - if (false) { // DEBUG to check logs in shutdown process - // startup AB - startA(); - startB(); // need to see log of shutdown problem - } + // startup AB + startA(); + startB(); // need to see log of shutdown problem awaitMetQuorum(); @@ -1706,8 +1704,10 @@ } - // FIXME: The order of the destroy IS significant since a reorganisation - // on shutdown is another specific problem right now + /* + * Note: The order of the destroy IS significant since a + * reorganisation on shutdown is another specific problem right now. + */ destroyC(); destroyA(); destroyB(); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-11 16:02:54
|
Revision: 6980 http://bigdata.svn.sourceforge.net/bigdata/?rev=6980&view=rev Author: thompsonbry Date: 2013-03-11 16:02:46 +0000 (Mon, 11 Mar 2013) Log Message: ----------- Exposed public method for getCastVoteIfConsensus() and new test suites for pipeline reorg and getCastVoteIfConsensus() from Martyn. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/Quorum.java branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/TestZkHA3QuorumSemantics.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-03-11 15:44:56 UTC (rev 6979) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/AbstractQuorum.java 2013-03-11 16:02:46 UTC (rev 6980) @@ -896,21 +896,7 @@ } } - /* - * Helper methods. - */ - - /** - * Search for the vote for the service. - * - * @param serviceId - * The service identifier. - * - * @return The lastCommitTime for which the service has cast its vote -or- - * <code>null</code> if the service is not participating in a - * consensus. - */ - private Long getCastVoteIfConsensus(final UUID serviceId) { + public Long getCastVoteIfConsensus(final UUID serviceId) { lock.lock(); try { final Iterator<Map.Entry<Long, LinkedHashSet<UUID>>> itr = votes @@ -932,6 +918,10 @@ } } + /* + * Helper methods. + */ + // /** // * Search for the vote for the service. // * Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/Quorum.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/Quorum.java 2013-03-11 15:44:56 UTC (rev 6979) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/quorum/Quorum.java 2013-03-11 16:02:46 UTC (rev 6980) @@ -224,6 +224,18 @@ Long getCastVote(final UUID serviceId); /** + * Search for the vote for the service. + * + * @param serviceId + * The service identifier. + * + * @return The lastCommitTime for which the service has cast its vote -or- + * <code>null</code> if the service is not participating in a + * consensus. + */ + Long getCastVoteIfConsensus(final UUID serviceId); + + /** * Return the identifiers for the member services joined with this quorum. * If the quorum was met at the moment the request was processed, then the * first element of the array was the quorum leader as of that moment and Modified: branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java =================================================================== --- branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java 2013-03-11 15:44:56 UTC (rev 6979) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/quorum/TestHA3QuorumSemantics.java 2013-03-11 16:02:46 UTC (rev 6980) @@ -27,6 +27,7 @@ package com.bigdata.quorum; +import java.util.Arrays; import java.util.Map; import java.util.UUID; @@ -1234,4 +1235,157 @@ } + + /** + * Variations on standard pipelineReorganization to test conditions that + * occasionally fail in TestHA3 + * + * @throws InterruptedException + */ + public void test_pipelineReorganization2() throws InterruptedException { + + final Quorum<?, ?> quorum0 = quorums[0]; + final MockQuorumMember<?> client0 = clients[0]; + final QuorumActor<?, ?> actor0 = actors[0]; + final UUID serviceId0 = client0.getServiceId(); + + final Quorum<?, ?> quorum1 = quorums[1]; + final MockQuorumMember<?> client1 = clients[1]; + final QuorumActor<?, ?> actor1 = actors[1]; + final UUID serviceId1 = client1.getServiceId(); + + final Quorum<?, ?> quorum2 = quorums[2]; + final MockQuorumMember<?> client2 = clients[2]; + final QuorumActor<?, ?> actor2 = actors[2]; + final UUID serviceId2 = client2.getServiceId(); + + final long lastCommitTime = 0L; + + // declare the services as a quorum members. + actor0.memberAdd(); + actor1.memberAdd(); + actor2.memberAdd(); + + /* + * Have the services join the pipeline a different order from the order + * in which they will cast their votes. + */ + actor2.pipelineAdd(); + actor1.pipelineAdd(); + actor0.pipelineAdd(); + + assertCondition(new Runnable() { + public void run() { + /* + * The service which we will cause to vote first (and hence will + * become the leader) is NOT at the head of the pipeline. + */ + assertEquals(new UUID[] { serviceId2, serviceId1, serviceId0 }, + quorum0.getPipeline()); + assertEquals(new UUID[] { serviceId2, serviceId1, serviceId0 }, + quorum1.getPipeline()); + assertEquals(new UUID[] { serviceId2, serviceId1, serviceId0 }, + quorum2.getPipeline()); + } + }); + + /* + * Have two services cast a vote for a lastCommitTime. This will cause + * the quorum to meet. + * + * But actor2 should be moved to end of pipeline + */ + final long token1; + { + + actor1.castVote(lastCommitTime); + actor0.castVote(lastCommitTime); + + // validate the token was assigned. + log.warn("Awaiting quorums to report met."); + token1 = quorum0.awaitQuorum(); + log.warn("Quorum0 reports met."); + assertEquals(token1, quorum1.awaitQuorum()); + log.warn("Quorum1 reports met."); + assertEquals(token1, quorum2.awaitQuorum()); + log.warn("Quorum2 reports met."); + assertEquals(token1, quorum1.lastValidToken()); + assertEquals(token1, quorum2.lastValidToken()); + assertEquals(Quorum.NO_QUORUM + 1, quorum0.lastValidToken()); + assertEquals(Quorum.NO_QUORUM + 1, quorum0.token()); + assertTrue(quorum0.isQuorumMet()); + + assertCondition(new Runnable() { + public void run() { + + // services have voted for a single lastCommitTime. + assertEquals(1, quorum0.getVotes().size()); + assertEquals(1, quorum1.getVotes().size()); + assertEquals(1, quorum2.getVotes().size()); + + // verify the vote order. + log.warn("expected: " + + Arrays.toString(new UUID[] { serviceId1, + serviceId0 })); + log.warn("actual : " + + Arrays.toString(quorum0.getVotes().get( + lastCommitTime))); + + assertEquals(new UUID[] { serviceId1, serviceId0 }, quorum0 + .getVotes().get(lastCommitTime)); + assertEquals(new UUID[] { serviceId1, serviceId0 }, quorum1 + .getVotes().get(lastCommitTime)); + assertEquals(new UUID[] { serviceId1, serviceId0 }, quorum2 + .getVotes().get(lastCommitTime)); + + // verify the consensus was updated. + assertEquals(lastCommitTime, client0.lastConsensusValue); + assertEquals(lastCommitTime, client1.lastConsensusValue); + assertEquals(lastCommitTime, client2.lastConsensusValue); + + /* + * Service join in the same order in which they cast their + * votes. + */ + assertEquals(new UUID[] { serviceId1, serviceId0 }, + quorum0.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0 }, + quorum1.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0 }, + quorum2.getJoined()); + + // The leader is now at the front of the pipeline, with + // service2 moved to end. + assertEquals(new UUID[] { serviceId1, serviceId0, + serviceId2 }, quorum0.getPipeline()); + assertEquals(new UUID[] { serviceId1, serviceId0, + serviceId2 }, quorum1.getPipeline()); + assertEquals(new UUID[] { serviceId1, serviceId0, + serviceId2 }, quorum2.getPipeline()); + + } + }); + + // check votes cast + assertTrue(quorum1.getCastVote(serviceId1) == quorum1.getCastVoteIfConsensus(serviceId0)); + assertTrue(quorum1.getCastVote(serviceId1) != quorum1.getCastVote(serviceId2)); + actor2.castVote(lastCommitTime); + assertTrue(quorum1.getCastVoteIfConsensus(serviceId1) == quorum1.getCastVoteIfConsensus(serviceId2)); + + Thread.sleep(100); + + final long token = quorum2.awaitQuorum(); + + assertTrue(quorum2.isQuorumFullyMet(token)); + + assertEquals(new UUID[] { serviceId1, serviceId0, serviceId2 }, + quorum0.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0, serviceId2 }, + quorum1.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0, serviceId2 }, + quorum2.getJoined()); + } + + } + } Modified: branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/TestZkHA3QuorumSemantics.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/TestZkHA3QuorumSemantics.java 2013-03-11 15:44:56 UTC (rev 6979) +++ branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/quorum/zk/TestZkHA3QuorumSemantics.java 2013-03-11 16:02:46 UTC (rev 6980) @@ -1214,4 +1214,157 @@ } + + /** + * Variations on standard pipelineReorganization to test conditions that + * occasionally fail in TestHA3 + * + * @throws InterruptedException + */ + public void test_pipelineReorganization2() throws InterruptedException { + + final Quorum<?, ?> quorum0 = quorums[0]; + final MockQuorumMember<?> client0 = clients[0]; + final QuorumActor<?, ?> actor0 = actors[0]; + final UUID serviceId0 = client0.getServiceId(); + + final Quorum<?, ?> quorum1 = quorums[1]; + final MockQuorumMember<?> client1 = clients[1]; + final QuorumActor<?, ?> actor1 = actors[1]; + final UUID serviceId1 = client1.getServiceId(); + + final Quorum<?, ?> quorum2 = quorums[2]; + final MockQuorumMember<?> client2 = clients[2]; + final QuorumActor<?, ?> actor2 = actors[2]; + final UUID serviceId2 = client2.getServiceId(); + + final long lastCommitTime = 0L; + + // declare the services as a quorum members. + actor0.memberAdd(); + actor1.memberAdd(); + actor2.memberAdd(); + + /* + * Have the services join the pipeline a different order from the order + * in which they will cast their votes. + */ + actor2.pipelineAdd(); + actor1.pipelineAdd(); + actor0.pipelineAdd(); + + assertCondition(new Runnable() { + public void run() { + /* + * The service which we will cause to vote first (and hence will + * become the leader) is NOT at the head of the pipeline. + */ + assertEquals(new UUID[] { serviceId2, serviceId1, serviceId0 }, + quorum0.getPipeline()); + assertEquals(new UUID[] { serviceId2, serviceId1, serviceId0 }, + quorum1.getPipeline()); + assertEquals(new UUID[] { serviceId2, serviceId1, serviceId0 }, + quorum2.getPipeline()); + } + }); + + /* + * Have two services cast a vote for a lastCommitTime. This will cause + * the quorum to meet. + * + * But actor2 should be moved to end of pipeline + */ + final long token1; + { + + actor1.castVote(lastCommitTime); + actor0.castVote(lastCommitTime); + + // validate the token was assigned. + log.warn("Awaiting quorums to report met."); + token1 = quorum0.awaitQuorum(); + log.warn("Quorum0 reports met."); + assertEquals(token1, quorum1.awaitQuorum()); + log.warn("Quorum1 reports met."); + assertEquals(token1, quorum2.awaitQuorum()); + log.warn("Quorum2 reports met."); + assertEquals(token1, quorum1.lastValidToken()); + assertEquals(token1, quorum2.lastValidToken()); + assertEquals(Quorum.NO_QUORUM + 1, quorum0.lastValidToken()); + assertEquals(Quorum.NO_QUORUM + 1, quorum0.token()); + assertTrue(quorum0.isQuorumMet()); + + assertCondition(new Runnable() { + public void run() { + + // services have voted for a single lastCommitTime. + assertEquals(1, quorum0.getVotes().size()); + assertEquals(1, quorum1.getVotes().size()); + assertEquals(1, quorum2.getVotes().size()); + + // verify the vote order. + log.warn("expected: " + + Arrays.toString(new UUID[] { serviceId1, + serviceId0 })); + log.warn("actual : " + + Arrays.toString(quorum0.getVotes().get( + lastCommitTime))); + + assertEquals(new UUID[] { serviceId1, serviceId0 }, quorum0 + .getVotes().get(lastCommitTime)); + assertEquals(new UUID[] { serviceId1, serviceId0 }, quorum1 + .getVotes().get(lastCommitTime)); + assertEquals(new UUID[] { serviceId1, serviceId0 }, quorum2 + .getVotes().get(lastCommitTime)); + + // verify the consensus was updated. + assertEquals(lastCommitTime, client0.lastConsensusValue); + assertEquals(lastCommitTime, client1.lastConsensusValue); + assertEquals(lastCommitTime, client2.lastConsensusValue); + + /* + * Service join in the same order in which they cast their + * votes. + */ + assertEquals(new UUID[] { serviceId1, serviceId0 }, + quorum0.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0 }, + quorum1.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0 }, + quorum2.getJoined()); + + // The leader is now at the front of the pipeline, with + // service2 moved to end. + assertEquals(new UUID[] { serviceId1, serviceId0, + serviceId2 }, quorum0.getPipeline()); + assertEquals(new UUID[] { serviceId1, serviceId0, + serviceId2 }, quorum1.getPipeline()); + assertEquals(new UUID[] { serviceId1, serviceId0, + serviceId2 }, quorum2.getPipeline()); + + } + }); + + // check votes cast + assertTrue(quorum1.getCastVote(serviceId1) == quorum1.getCastVoteIfConsensus(serviceId0)); + assertTrue(quorum1.getCastVote(serviceId1) != quorum1.getCastVote(serviceId2)); + actor2.castVote(lastCommitTime); + assertTrue(quorum1.getCastVoteIfConsensus(serviceId1) == quorum1.getCastVoteIfConsensus(serviceId2)); + + Thread.sleep(100); + + final long token = quorum2.awaitQuorum(); + + assertTrue(quorum2.isQuorumFullyMet(token)); + + assertEquals(new UUID[] { serviceId1, serviceId0, serviceId2 }, + quorum0.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0, serviceId2 }, + quorum1.getJoined()); + assertEquals(new UUID[] { serviceId1, serviceId0, serviceId2 }, + quorum2.getJoined()); + } + + } + } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-12 16:03:58
|
Revision: 6984 http://bigdata.svn.sourceforge.net/bigdata/?rev=6984&view=rev Author: thompsonbry Date: 2013-03-12 16:03:48 +0000 (Tue, 12 Mar 2013) Log Message: ----------- Added a method that can be used to force the HAJournalServer into an error state. From that error state, it will attempt to recover automatically. This method is intended for use by the HA test suite. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlue.java branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlue.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlue.java 2013-03-12 11:07:03 UTC (rev 6983) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlue.java 2013-03-12 16:03:48 UTC (rev 6984) @@ -72,13 +72,23 @@ * its zookeeper connection. This is a drastic action which will cause all * <i>ephemeral</i> tokens for that service to be retracted from zookeeper. * When the service reconnects, it will reestablish those connections. + * <p> + * Note: This method is intended primarily as an aid in writing various HA + * unit tests. * - * @todo Good idea? Bad idea? - * * @see http://wiki.apache.org/hadoop/ZooKeeper/FAQ#A4 */ public Future<Void> bounceZookeeperConnection() throws IOException; + /** + * Force the end point to enter into an error state from which it will + * naturally move back into a consistent state. + * <p> + * Note: This method is intended primarily as an aid in writing various HA + * unit tests. + */ + public Future<Void> enterErrorState() throws IOException; + /* * Synchronization. * Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java 2013-03-12 11:07:03 UTC (rev 6983) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/HAGlueDelegate.java 2013-03-12 16:03:48 UTC (rev 6984) @@ -30,8 +30,10 @@ import java.security.NoSuchAlgorithmException; import java.util.UUID; import java.util.concurrent.Future; +import java.util.concurrent.FutureTask; import java.util.concurrent.TimeoutException; +import com.bigdata.concurrent.FutureTaskMon; import com.bigdata.ha.msg.IHA2PhaseAbortMessage; import com.bigdata.ha.msg.IHA2PhaseCommitMessage; import com.bigdata.ha.msg.IHA2PhasePrepareMessage; @@ -73,46 +75,61 @@ } + @Override public Future<Void> bounceZookeeperConnection() throws IOException { return delegate.bounceZookeeperConnection(); } + @Override + public Future<Void> enterErrorState() throws IOException { + return delegate.enterErrorState(); + } + + @Override public UUID getServiceId() throws IOException { return delegate.getServiceId(); } + @Override public Future<Boolean> prepare2Phase(IHA2PhasePrepareMessage msg) throws IOException { return delegate.prepare2Phase(msg); } + @Override public Future<IHAReadResponse> readFromDisk( IHAReadRequest readMessage) throws IOException { return delegate.readFromDisk(readMessage); } + @Override public InetSocketAddress getWritePipelineAddr() throws IOException { return delegate.getWritePipelineAddr(); } + @Override public IHARootBlockResponse getRootBlock(IHARootBlockRequest msg) throws IOException { return delegate.getRootBlock(msg); } + @Override public Future<Void> moveToEndOfPipeline() throws IOException { return delegate.moveToEndOfPipeline(); } + @Override public Future<Void> commit2Phase(IHA2PhaseCommitMessage commitMessage) throws IOException { return delegate.commit2Phase(commitMessage); } + @Override public Future<Void> abort2Phase(IHA2PhaseAbortMessage abortMessage) throws IOException { return delegate.abort2Phase(abortMessage); } + @Override public Future<Void> receiveAndReplicate(final IHASyncRequest req, final IHAWriteMessage msg) throws IOException { return delegate.receiveAndReplicate(req, msg); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-12 11:07:03 UTC (rev 6983) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-12 16:03:48 UTC (rev 6984) @@ -6038,15 +6038,24 @@ public Future<Void> bounceZookeeperConnection() { final FutureTask<Void> ft = new FutureTaskMon<Void>(new Runnable() { public void run() { - // NOP (no zookeeper at this layer). - if (haLog.isInfoEnabled()) - haLog.info(""); + // NOP (not implemented at this layer). } }, null); ft.run(); return getProxy(ft); } + @Override + public Future<Void> enterErrorState() { + final FutureTask<Void> ft = new FutureTaskMon<Void>(new Runnable() { + public void run() { + // NOP (not implemented at this layer). + } + }, null); + ft.run(); + return getProxy(ft); + } + /** * {@inheritDoc} * <p> Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-03-12 11:07:03 UTC (rev 6983) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-03-12 16:03:48 UTC (rev 6984) @@ -92,6 +92,7 @@ import com.bigdata.journal.ValidationError; import com.bigdata.journal.WORMStrategy; import com.bigdata.journal.WriteExecutorService; +import com.bigdata.journal.jini.ha.HAJournalServer.HAQuorumService; import com.bigdata.quorum.AsynchronousQuorumCloseException; import com.bigdata.quorum.Quorum; import com.bigdata.quorum.zk.ZKQuorumImpl; @@ -572,7 +573,7 @@ protected HAGlueService(final UUID serviceId) { super(serviceId, writePipelineAddr); - + } /* @@ -1314,6 +1315,37 @@ } + @Override + public Future<Void> enterErrorState() { + + final FutureTask<Void> ft = new FutureTaskMon<Void>( + new EnterErrorStateTask(), null/* result */); + + ft.run(); + + return getProxy(ft); + + } + + private class EnterErrorStateTask implements Runnable { + + public void run() { + + @SuppressWarnings("unchecked") + final HAQuorumService<HAGlue, HAJournal> service = (HAQuorumService<HAGlue, HAJournal>) getQuorum() + .getClient(); + + // Note: Local method call on AbstractJournal. + final UUID serviceId = getServiceId(); + + haLog.warn("ENTERING ERROR STATE: " + serviceId); + + service.enterErrorState(); + + } + + } + /** * Note: The invocation layer factory is reused for each exported proxy (but * the exporter itself is paired 1:1 with the exported proxy). Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-12 11:07:03 UTC (rev 6983) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-12 16:03:48 UTC (rev 6984) @@ -647,7 +647,8 @@ * Concrete {@link QuorumServiceBase} implementation for the * {@link HAJournal}. */ - static private class HAQuorumService<S extends HAGlue, L extends HAJournal> + // Note: Exposed to HAJournal.enterErrorState() + static /*private*/ class HAQuorumService<S extends HAGlue, L extends HAJournal> extends QuorumServiceBase<S, L> { private final L journal; @@ -841,6 +842,12 @@ } } // RunStateCallable + + void enterErrorState() { + + enterRunState(new ErrorTask()); + + } /** * Change the run state. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <tho...@us...> - 2013-03-15 20:33:38
|
Revision: 6999 http://bigdata.svn.sourceforge.net/bigdata/?rev=6999&view=rev Author: thompsonbry Date: 2013-03-15 20:33:26 +0000 (Fri, 15 Mar 2013) Log Message: ----------- Checkpoint on refactoring to support snapshots (HA onlone backup). - Moved HALog property to HAJournalServer Configuration, reorganized how we handle the HAJournal initialization to use Configuration in preference to Properties for anything not already declared by Journal.Options. - Added HAJournalServer configuration options for snapshotDir, snapshotPolicy, and restorePolicy. - Added interfaces and implementations for ISnapshotPolicy and IRestorePolicy. - Removed QUORUM_BACKUP and QuourmBackupState. - Added logic to remove old snapshots and modified the logic to remove old HALogs to be snapshot aware. - Added HAJournal.snapshotIndex. The index is populated from the file system when the service starts. - Refactored logic into SnapshotManager. HA tests are green with the included configuration files. Modified Paths: -------------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-A.config branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-B.config branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal-C.config branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/ZKQuorum.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3JournalServerTestCase.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/HAJournal-A.config branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/HAJournal-B.config branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/HAJournal-C.config branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHAJournalServer.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/log4j-template-A.properties branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/log4j-template-B.properties branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/log4j-template-C.properties branches/READ_CACHE/src/resources/HAJournal/HAJournal.config Added Paths: ----------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/CommitTimeIndex.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultRestorePolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ForeverRestorePolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/IRestorePolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ISnapshotPolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/NoRestorePolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/NoSnapshotPolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java Removed Paths: ------------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/quorum/zk/QuorumBackupState.java Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/CommitTimeIndex.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/CommitTimeIndex.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/CommitTimeIndex.java 2013-03-15 20:33:26 UTC (rev 6999) @@ -0,0 +1,374 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. 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.jini.ha; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.nio.ByteBuffer; +import java.util.UUID; + +import com.bigdata.btree.BTree; +import com.bigdata.btree.BytesUtil; +import com.bigdata.btree.Checkpoint; +import com.bigdata.btree.DefaultTupleSerializer; +import com.bigdata.btree.ITuple; +import com.bigdata.btree.IndexMetadata; +import com.bigdata.btree.keys.ASCIIKeyBuilderFactory; +import com.bigdata.btree.keys.IKeyBuilder; +import com.bigdata.btree.keys.IKeyBuilderFactory; +import com.bigdata.btree.keys.KeyBuilder; +import com.bigdata.journal.ICommitRecord; +import com.bigdata.journal.IRootBlockView; +import com.bigdata.journal.RootBlockView; +import com.bigdata.rawstore.Bytes; +import com.bigdata.rawstore.IRawStore; +import com.bigdata.util.ChecksumUtility; + +/** + * {@link BTree} mapping <em>commitTime</em> (long integers) to + * {@link IRootBlockView} records. + * <p> + * Note: Access to this object MUST be synchronized. + * <p> + * Note: This is used as a transient data structure that is populated from the + * file system by the {@link HAJournalServer}. A separate instance is maintained + * for the HALog files and the snapshot files. + */ +public class CommitTimeIndex extends BTree { + + /** + * Instance used to encode the timestamp into the key. + */ + final private IKeyBuilder keyBuilder = new KeyBuilder(Bytes.SIZEOF_LONG); + + /** + * Create a transient instance. + * + * @return The new instance. + */ + static public CommitTimeIndex createTransient() { + + final IndexMetadata metadata = new IndexMetadata(UUID.randomUUID()); + + metadata.setBTreeClassName(CommitTimeIndex.class.getName()); + + metadata.setTupleSerializer(new TupleSerializer( + new ASCIIKeyBuilderFactory(Bytes.SIZEOF_LONG))); + + return (CommitTimeIndex) BTree.createTransient(/*store, */metadata); + + } + + /** + * Load from the store. + * + * @param store + * The backing store. + * @param checkpoint + * The {@link Checkpoint} record. + * @param metadata + * The metadata record for the index. + */ + public CommitTimeIndex(final IRawStore store, final Checkpoint checkpoint, + final IndexMetadata metadata, final boolean readOnly) { + + super(store, checkpoint, metadata, readOnly); + + } + + /** + * Encodes the commit time into a key. + * + * @param commitTime + * The commit time. + * + * @return The corresponding key. + */ + private byte[] getKey(final long commitTime) { + + return keyBuilder.reset().append(commitTime).getKey(); + + } + + /** + * Return the {@link IRootBlock} identifying the journal having the largest + * commitTime that is less than or equal to the given timestamp. This is + * used primarily to locate the commit record that will serve as the ground + * state for a transaction having <i>timestamp</i> as its start time. In + * this context the LTE search identifies the most recent commit state that + * not later than the start time of the transaction. + * + * @param timestamp + * The given timestamp. + * + * @return The description of the relevant journal resource -or- + * <code>null</code> iff there are no journals in the index that + * satisify the probe. + * + * @throws IllegalArgumentException + * if <i>timestamp</i> is less than or equals to ZERO (0L). + */ + synchronized public IRootBlockView find(final long timestamp) { + + if (timestamp <= 0L) + throw new IllegalArgumentException(); + + // find (first less than or equal to). + final long index = findIndexOf(timestamp); + + if(index == -1) { + + // No match. + log.warn("Not found: " + timestamp); + + return null; + + } + + return valueAtIndex(index); + + } + + /** + * Retrieve the entry from the index. + */ + private IRootBlockView valueAtIndex(final long index) { + + final byte[] val = super.valueAt(index); + + assert val != null : "Entry has null value: index=" + index; + + final IRootBlockView entry = new RootBlockView(false/* rootBlock0 */, + ByteBuffer.wrap(val), ChecksumUtility.getCHK()); + + return entry; + + } + + /** + * Find the first journal whose <em>createTime</em> is strictly greater + * than the timestamp. + * + * @param timestamp + * The timestamp. A value of ZERO (0) may be used to find the + * first journal. + * + * @return The commit record -or- <code>null</code> if there is no commit + * record whose timestamp is strictly greater than <i>timestamp</i>. + */ + synchronized public IRootBlockView findNext(final long timestamp) { + + /* + * Note: can also be written using rangeIterator().next(). + */ + + if (timestamp < 0L) + throw new IllegalArgumentException(); + + // find first strictly greater than. + final long index = findIndexOf(Math.abs(timestamp)) + 1; + + if (index == nentries) { + + // No match. + + return null; + + } + + return valueAtIndex(index); + + } + + /** + * Find the index of the {@link ICommitRecord} having the largest timestamp + * that is less than or equal to the given timestamp. + * + * @return The index of the {@link ICommitRecord} having the largest + * timestamp that is less than or equal to the given timestamp -or- + * <code>-1</code> iff there are no {@link ICommitRecord}s + * defined. + */ + synchronized public long findIndexOf(final long timestamp) { + + long pos = super.indexOf(getKey(timestamp)); + + if (pos < 0) { + + /* + * the key lies between the entries in the index, or possible before + * the first entry in the index. [pos] represents the insert + * position. we convert it to an entry index and subtract one to get + * the index of the first commit record less than the given + * timestamp. + */ + + pos = -(pos+1); + + if(pos == 0) { + + // No entry is less than or equal to this timestamp. + return -1; + + } + + pos--; + + return pos; + + } else { + + /* + * exact hit on an entry. + */ + + return pos; + + } + + } + + /** + * Add an entry under the commitTime associated with the + * {@link IRootBlockView} record. + * + * @param rootBlock + * The {@link IRootBlockView} record. + * + * @exception IllegalArgumentException + * if <i>commitTime</i> is <code>0L</code>. + * @exception IllegalArgumentException + * if <i>rootBLock</i> is <code>null</code>. + * @exception IllegalArgumentException + * if there is already an entry registered under for the + * given timestamp. + */ + synchronized public void add(final IRootBlockView rootBlock) { + + if (rootBlock == null) + throw new IllegalArgumentException(); + + final long createTime = rootBlock.getLastCommitTime(); + + if (createTime == 0L) + throw new IllegalArgumentException(); + + final byte[] key = getKey(createTime); + + if(super.contains(key)) { + + throw new IllegalArgumentException("entry exists: timestamp=" + + createTime); + + } + + // add a serialized entry to the persistent index. + super.insert(key, BytesUtil.getBytes(rootBlock.asReadOnlyBuffer())); + + } + + /** + * Encapsulates key and value formation. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * @version $Id: JournalIndex.java 5892 2012-01-27 13:22:11Z thompsonbry $ + */ + static protected class TupleSerializer extends + DefaultTupleSerializer<Long, IRootBlockView> { + + /** + * + */ + private static final long serialVersionUID = -2851852959439807542L; + + /** + * De-serialization ctor. + */ + public TupleSerializer() { + + super(); + + } + + /** + * Ctor when creating a new instance. + * + * @param keyBuilderFactory + */ + public TupleSerializer(final IKeyBuilderFactory keyBuilderFactory) { + + super(keyBuilderFactory); + + } + + /** + * Decodes the key as a commit time. + */ + @Override + public Long deserializeKey(ITuple tuple) { + + return KeyBuilder + .decodeLong(tuple.getKeyBuffer().array(), 0/* offset */); + + } + + /** + * The initial version (no additional persistent state). + */ + private final static transient byte VERSION0 = 0; + + /** + * The current version. + */ + private final static transient byte VERSION = VERSION0; + + public void readExternal(final ObjectInput in) throws IOException, + ClassNotFoundException { + + super.readExternal(in); + + final byte version = in.readByte(); + + switch (version) { + case VERSION0: + break; + default: + throw new UnsupportedOperationException("Unknown version: " + + version); + } + + } + + public void writeExternal(final ObjectOutput out) throws IOException { + + super.writeExternal(out); + + out.writeByte(VERSION); + + } + + } + +} Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultRestorePolicy.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultRestorePolicy.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultRestorePolicy.java 2013-03-15 20:33:26 UTC (rev 6999) @@ -0,0 +1,92 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. 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.jini.ha; + +import java.util.concurrent.TimeUnit; + +import com.bigdata.journal.IRootBlockView; + +/** + * The default restore policy. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public class DefaultRestorePolicy implements IRestorePolicy { + + private final long millis; + + /** + * The default is to keep local backups on hand for 7 days. + */ + public DefaultRestorePolicy() { + + this(TimeUnit.DAYS.toMillis(7)); + + } + + /** + * Create a policy that will keep local backups on hand for the specified + * number of milliseconds. + * + * @param millis + * The #of milliseconds of state that can be restored from local + * backups. + */ + public DefaultRestorePolicy(final long millis) { + + if (millis < 0) + throw new IllegalArgumentException(); + + this.millis = millis; + + } + + /** + * This finds and returns the commit counter for the most recent snapshot + * whose commit time is LTE <code>now - millis</code>, where <i>millis</i> + * is the #of milliseconds specified by the constructor for this policy. The + * return value will be ZERO (0) if there are no commit points. + */ + @Override + public long getEarliestRestorableCommitPoint(final HAJournal jnl) { + + final long now = System.currentTimeMillis(); + + final long then = now - millis; + + final IRootBlockView rootBlock = jnl.getSnapshotManager() + .getSnapshotIndex().find(then); + + if (rootBlock == null) { + + // There are no snapshots. + return 0L; + + } + + return rootBlock.getCommitCounter(); + + } + +} Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java 2013-03-15 20:33:26 UTC (rev 6999) @@ -0,0 +1,182 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2013. 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.jini.ha; + +import java.lang.ref.WeakReference; +import java.util.Calendar; +import java.util.concurrent.TimeUnit; + +import org.apache.log4j.Logger; + +/** + * Policy schedules a snapshot at the same time each day. A threshold is used to + * skip the backup if the HALog delta is LTE a specified percentage of the size + * of the journal on the disk. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public class DefaultSnapshotPolicy implements ISnapshotPolicy { + + private static final transient Logger log = Logger + .getLogger(DefaultSnapshotPolicy.class); + + final private int timeOfDay; + final private int percentLogSize; + + /** + * The default policy wakes up at <code>0200</code> and takes a snapshot if + * the size of the HALogs written since the last snapshot is at least + * <code>50%</code> of the size of the journal on the disk. + */ + public DefaultSnapshotPolicy() { + + this(200/* 0200 hours */, 50/* percent */); + + } + + /** + * + * @param timeOfDay + * The time of day to wake up and decide whether or not to make a + * new snapshot. + * @param percentLogSize + * The threshold at which a new snapshot will be made. This is + * expressed as a percentage of the HALog size on the disk for + * those HALog files written since the last snapshot (or all + * HALogs if no snapshot has been taken yet). + */ + public DefaultSnapshotPolicy(final int timeOfDay, final int percentLogSize) { + + if (timeOfDay < 0) + throw new IllegalArgumentException(); + + if (percentLogSize < 10 || percentLogSize > 400) + throw new IllegalArgumentException("percentage must be in [10:400]"); + + this.timeOfDay = timeOfDay; + + this.percentLogSize = percentLogSize; + + } + + public void init(final HAJournal jnl) { + + final long initialDelay = delay(timeOfDay); + + jnl.addScheduledTask(new SnapshotTask(jnl), initialDelay, 1/* delay */, + TimeUnit.DAYS); + + } + + private class SnapshotTask implements Runnable { + + /** + * Note: Weak reference prevents the Journal from being pinned. + */ + private final WeakReference<HAJournal> ref; + + public SnapshotTask(final HAJournal jnl) { + + this.ref = new WeakReference<HAJournal>(jnl); + + } + + /** + * Note: Do not throw anything out of this method or it will cause the + * task to not be rescheduled! + */ + @Override + public void run() { + + try { + + final HAJournal jnl = ref.get(); + + if (jnl == null) + return; + + jnl.getSnapshotManager().takeSnapshot(percentLogSize); + + } catch (Throwable t) { + + log.error(t, t); + + } + + } + + } + + /** + * Return the delay (milliseconds) until the given time of day. The time of + * day is expressed as a single integer <code>hhmm</code>. + * + * @param tod + * The time of day expressed as a single integer + * <code>hhmm</code>. + * + * @return The milliseconds until that time of day. + */ + static private long delay(final int tod) { + + final long minuteMillis = 60 * 1000; + final long dayMillis = 24 * 60 * minuteMillis; + + final int todHours = tod / 100; + final int todMinutes = tod % 100; + + final long todMillis = ((todHours * 60) + todMinutes) * minuteMillis; + + final long now = System.currentTimeMillis(); + + final long tzAdjust = Calendar.getInstance().getTimeZone() + .getRawOffset(); + + // days mod 24 * 60 * 60 * 1000 + final long startOfDay = now - (now % dayMillis) - tzAdjust; + +// final long startOfDay = now - (now % dayMillis); + + final long targetTime = startOfDay + todMillis; + + final long delayMs = targetTime - now; + + if (delayMs < 0) { + + return delayMs + dayMillis; + + } else { + + return delayMs; + + } + + } + +// public static void main(String[] args) { +// System.out.println("1540 delay: " + delay(1540)); +// System.out.println("1330 delay: " + delay(1330)); +// } + +} Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ForeverRestorePolicy.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ForeverRestorePolicy.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ForeverRestorePolicy.java 2013-03-15 20:33:26 UTC (rev 6999) @@ -0,0 +1,49 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. 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.jini.ha; + +/** + * A policy that never permits the release of backups such that you can always + * restore any commit point. This policy will require unbounded disk space if + * there are continuing update transactions against the database. However, it is + * perfectly reasonable if you are using a write-once, read-many deployment + * strategy. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + */ +public class ForeverRestorePolicy implements IRestorePolicy { + + /** + * {@inheritDoc} + * <p> + * This policy always returns ZERO to prevent backups from being released. + */ + @Override + public long getEarliestRestorableCommitPoint(HAJournal jnl) { + + return 0; + + } + +} Deleted: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-03-15 20:31:28 UTC (rev 6998) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HABackupManager.java 2013-03-15 20:33:26 UTC (rev 6999) @@ -1,1222 +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.jini.ha; - -import java.io.File; -import java.io.IOException; -import java.net.BindException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.nio.ByteBuffer; -import java.rmi.Remote; -import java.util.Arrays; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.Executor; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; - -import net.jini.config.Configuration; -import net.jini.config.ConfigurationException; -import net.jini.config.ConfigurationProvider; -import net.jini.core.entry.Entry; -import net.jini.core.lookup.ServiceItem; -import net.jini.core.lookup.ServiceRegistrar; -import net.jini.discovery.LookupDiscoveryManager; -import net.jini.lease.LeaseRenewalManager; -import net.jini.lookup.ServiceDiscoveryManager; - -import org.apache.log4j.Logger; -import org.apache.zookeeper.CreateMode; -import org.apache.zookeeper.KeeperException.NodeExistsException; -import org.apache.zookeeper.data.ACL; - -import com.bigdata.Banner; -import com.bigdata.ha.HAGlue; -import com.bigdata.ha.HAPipelineGlue; -import com.bigdata.ha.QuorumPipelineImpl; -import com.bigdata.ha.QuorumService; -import com.bigdata.ha.msg.HARebuildRequest; -import com.bigdata.ha.msg.IHALogRequest; -import com.bigdata.ha.msg.IHALogRootBlocksRequest; -import com.bigdata.ha.msg.IHALogRootBlocksResponse; -import com.bigdata.ha.msg.IHARebuildRequest; -import com.bigdata.ha.msg.IHASendStoreResponse; -import com.bigdata.ha.msg.IHASyncRequest; -import com.bigdata.ha.msg.IHAWriteMessage; -import com.bigdata.ha.msg.IHAWriteSetStateRequest; -import com.bigdata.ha.msg.IHAWriteSetStateResponse; -import com.bigdata.io.SerializerUtil; -import com.bigdata.jini.start.config.ZookeeperClientConfig; -import com.bigdata.journal.IRootBlockView; -import com.bigdata.quorum.AbstractQuorumMember; -import com.bigdata.quorum.Quorum; -import com.bigdata.quorum.QuorumEvent; -import com.bigdata.quorum.QuorumException; -import com.bigdata.quorum.QuorumListener; -import com.bigdata.quorum.zk.QuorumBackupState; -import com.bigdata.quorum.zk.ZKQuorum; -import com.bigdata.quorum.zk.ZKQuorumImpl; -import com.bigdata.service.jini.JiniClient; -import com.bigdata.service.jini.JiniClientConfig; -import com.bigdata.util.concurrent.DaemonThreadFactory; -import com.bigdata.zookeeper.ZooKeeperAccessor; - -/** - * Service for making full and incremental backups. - * - * FIXME This is completely non-functional code. I was just experimenting - * with creating a standalone utility. A functional version should be - * derived by refactoring AbstractServer, HAJournalServer, etc. - * - * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - */ -public class HABackupManager { - - private static final Logger log = Logger.getLogger(HAJournalServer.class); - - /** - * Logger for HA events. - */ - private static final Logger haLog = Logger.getLogger("com.bigdata.haLog"); - - /** - * Configuration options for the {@link HAJournalServer}. - */ - public interface ConfigurationOptions -// extends AbstractServer.ConfigurationOptions - { - - String COMPONENT = HABackupManager.class.getName(); - - /** - * The target replication factor (k). - * - * @see HAJournalServer.ConfigurationOptions#REPLICATION_FACTOR - */ - String REPLICATION_FACTOR = HAJournalServer.ConfigurationOptions.REPLICATION_FACTOR; - - /** - * The {@link InetSocketAddress} at which the {@link HABackupManager} - * receives replicated writes. - * - * @see HAJournalServer.ConfigurationOptions#WRITE_PIPELINE_ADDR - */ - String WRITE_PIPELINE_ADDR = HAJournalServer.ConfigurationOptions.WRITE_PIPELINE_ADDR; - - /** - * The logical service identifier for the {@link HAJournalServer} - * replication cluster that that will be backed up by this service. - * - * @see HAJournalServer.ConfigurationOptions#LOGICAL_SERVICE_ID - */ - String LOGICAL_SERVICE_ID = HAJournalServer.ConfigurationOptions.LOGICAL_SERVICE_ID; - - } - - private LookupDiscoveryManager lookupDiscoveryManager; - - private ServiceDiscoveryManager serviceDiscoveryManager; - - /** - * The {@link Configuration} read based on the args[] provided when the - * server is started. - */ - protected Configuration config; - - /** - * The timeout in milliseconds to await the discovery of a service if there - * is a cache miss (default {@value #DEFAULT_CACHE_MISS_TIMEOUT}). - */ - final protected long cacheMissTimeout; - - /** - * A randomly generated {@link UUID} that this utility uses to identify - * itself. - */ - private final UUID serviceId = UUID.randomUUID(); - - /** - * The directory for the service. This is the directory within which the - * {@link #serviceIdFile} exists. A service MAY have its own concept of a - * data directory, log directory, etc. which can be somewhere else. - */ - private File serviceDir; - - /** - * Caching discovery client for the {@link HAGlue} services. - */ - private HAJournalDiscoveryClient discoveryClient; - - private ZookeeperClientConfig zkClientConfig; - - private ZooKeeperAccessor zka; - - private Quorum<HAGlue, QuorumService<HAGlue>> quorum; - - /** - * The znode name for the logical service. - * - * @see ConfigurationOptions#LOGICAL_SERVICE_ID - */ - private String logicalServiceId; - - /** - * The zpath for the logical service. - * - * @see ConfigurationOptions#LOGICAL_SERVICE_ID - */ - private String logicalServiceZPath; - - /** - * The {@link MyQuorumMember}. - */ - private MyQuorumMember quorumMember; - - /** - * An object used to manage jini service registrar discovery. - */ - public LookupDiscoveryManager getDiscoveryManagement() { - - return lookupDiscoveryManager; - - } - - /** - * An object used to lookup services using the discovered service registars. - */ - public ServiceDiscoveryManager getServiceDiscoveryManager() { - - return serviceDiscoveryManager; - - } - - /** - * Runs {@link AbstractServer#shutdownNow()} and terminates all asynchronous - * processing, including discovery. This is used for the shutdown hook (^C). - * - * @author <a href="mailto:tho...@us...">Bryan - * Thompson</a> - */ - private static class ShutdownThread extends Thread { - - public ShutdownThread() { - - super("shutdownThread"); - - setDaemon(true); - - } - - public void run() { - - /* - * FIXME Interrupt the backup (if any). It is logically empty until - * we write the root blocks. Those need to BOTH be written - * atomically (tricky) -or- just write the same root block twice - * (sneaky). - */ - - } - - } - - private HABackupManager(final String[] args) throws ConfigurationException { - - /* - * The runtime shutdown hook appears to be a robust way to handle ^C by - * providing a clean service termination. - * - * Note: This is setup before we start any async threads, including - * service discovery. - */ - Runtime.getRuntime().addShutdownHook(new ShutdownThread()); - - // Show the copyright banner during startup. - Banner.banner(); - - AbstractServer.setSecurityManager(); - - /* - * Display the banner. - * - * Note: This also installs the UncaughtExceptionHandler. - * - * @see https://sourceforge.net/apps/trac/bigdata/ticket/601 - */ - Banner.banner(); - - /* - * Read jini configuration & service properties - */ - - List<Entry> entries = null; - - final String COMPONENT = getClass().getName(); - final JiniClientConfig jiniClientConfig; - { - - config = ConfigurationProvider.getInstance(args); - - cacheMissTimeout = (Long) config.getEntry(COMPONENT, - AbstractServer.ConfigurationOptions.CACHE_MISS_TIMEOUT, Long.TYPE, - AbstractServer.ConfigurationOptions.DEFAULT_CACHE_MISS_TIMEOUT); - - jiniClientConfig = new JiniClientConfig( - JiniClientConfig.Options.NAMESPACE, config); - - // convert Entry[] to a mutable list. - entries = new LinkedList<Entry>( - Arrays.asList((Entry[]) jiniClientConfig.entries)); - - if (log.isInfoEnabled()) - log.info(jiniClientConfig.toString()); - - } - - /* - * Make sure that the parent directory exists. - * - * Note: the parentDir will be null if the serviceIdFile is in the - * root directory or if it is specified as a filename without any - * parents in the path expression. Note that the file names a file - * in the current working directory in the latter case and the root - * always exists in the former - and in both of those cases we do - * not have to create the parent directory. - */ - serviceDir = (File) config.getEntry(COMPONENT, - AbstractServer.ConfigurationOptions.SERVICE_DIR, File.class); - - if (serviceDir != null && !serviceDir.exists()) { - - log.warn("Creating: " + serviceDir); - - serviceDir.mkdirs(); - - } - - try { - - /* - * Note: This class will perform multicast discovery if ALL_GROUPS - * is specified and otherwise requires you to specify one or more - * unicast locators (URIs of hosts running discovery services). As - * an alternative, you can use LookupDiscovery, which always does - * multicast discovery. - */ - lookupDiscoveryManager = new LookupDiscoveryManager( - jiniClientConfig.groups, jiniClientConfig.locators, - null /* DiscoveryListener */, config); - - /* - * Setup a helper class that will be notified as services join or - * leave the various registrars to which the data server is - * listening. - */ - try { - - serviceDiscoveryManager = new ServiceDiscoveryManager( - lookupDiscoveryManager, new LeaseRenewalManager(), - config); - - } catch (IOException ex) { - - throw new RuntimeException( - "Could not initiate service discovery manager", ex); - - } - - } catch (IOException ex) { - - fatal("Could not setup discovery", ex); - throw new AssertionError();// keep the compiler happy. - - } catch (ConfigurationException ex) { - - fatal("Could not setup discovery", ex); - throw new AssertionError();// keep the compiler happy. - - } - - /* - * Create the service object. - */ - try { - - /* - * Note: By creating the service object here rather than outside of - * the constructor we potentially create problems for subclasses of - * AbstractServer since their own constructor will not have been - * executed yet. - * - * Some of those problems are worked around using a JiniClient to - * handle all aspects of service discovery (how this service locates - * the other services in the federation). - * - * Note: If you explicitly assign values to those clients when the - * fields are declared, e.g., [timestampServiceClient=null] then the - * ctor will overwrite the values set by [newService] since it is - * running before those initializations are performed. This is - * really crufty, may be JVM dependent, and needs to be refactored - * to avoid this subclass ctor init problem. - */ - - if (log.isInfoEnabled()) - log.info("Creating service impl..."); - - // init. -// impl = - newService(config); - -// if (log.isInfoEnabled()) -// log.info("Service impl is " + impl); - - } catch(Exception ex) { - - fatal("Could not start service: "+this, ex); - throw new AssertionError();// keeps compiler happy. - } - - } - - protected void fatal(String msg, Throwable t) { - - log.fatal(msg, t); - - terminate(); - - System.exit(1); - - } - - /** - * Terminates service management threads. - * <p> - * Subclasses which start additional service management threads SHOULD - * extend this method to terminate those threads. The implementation should - * be <strong>synchronized</strong>, should conditionally terminate each - * thread, and should trap, log, and ignore all errors. - */ - private void terminate() { - - if (log.isInfoEnabled()) - log.info("Terminating service management threads."); - -// if (joinManager != null) { -// -// try { -// -// joinManager.terminate(); -// -// } catch (Throwable ex) { -// -// log.error("Could not terminate the join manager: " + this, ex); -// -// } finally { -// -// joinManager = null; -// -// } -// -// } - - if (serviceDiscoveryManager != null) { - - serviceDiscoveryManager.terminate(); - - serviceDiscoveryManager = null; - - } - - if (lookupDiscoveryManager != null) { - - lookupDiscoveryManager.terminate(); - - lookupDiscoveryManager = null; - - } - - } - - protected void newService(final Configuration config) - throws Exception { - - /* - * Verify discovery of at least one ServiceRegistrar. - */ - { - final long begin = System.currentTimeMillis(); - - ServiceRegistrar[] registrars = null; - - long elapsed = 0; - - while ((registrars == null || registrars.length == 0) - && elapsed < TimeUnit.SECONDS.toMillis(10)) { - - registrars = getDiscoveryManagement().getRegistrars(); - - Thread.sleep(100/* ms */); - - elapsed = System.currentTimeMillis() - begin; - - } - - if (registrars == null || registrars.length == 0) { - - throw new RuntimeException( - "Could not discover ServiceRegistrar(s)"); - - } - - if (log.isInfoEnabled()) { - log.info("Found " + registrars.length + " service registrars"); - } - - } - -// // Setup discovery for HAGlue clients. -// final HAJournalDiscoveryClient discoveryClient = new HAJournalDiscoveryClient( -// getServiceDiscoveryManager(), -// null/* serviceDiscoveryListener */, cacheMissTimeout); - - /* - * Setup the Quorum. - */ - - zkClientConfig = new ZookeeperClientConfig(config); - - // znode name for the logical service. - final String logicalServiceId = (String) config.getEntry( - ConfigurationOptions.COMPONENT, - ConfigurationOptions.LOGICAL_SERVICE_ID, String.class); - - final String logicalServiceZPathPrefix = zkClientConfig.zroot + "/" - + HAJournalServer.class.getName(); - - // zpath for the logical service. - final String logicalServiceZPath = logicalServiceZPathPrefix + "/" - + logicalServiceId; - - final int replicationFactor = (Integer) config.getEntry( - ConfigurationOptions.COMPONENT, - ConfigurationOptions.REPLICATION_FACTOR, Integer.TYPE); - - { - - // The address at which this service exposes its write pipeline. - final InetSocketAddress writePipelineAddr = (InetSocketAddress) config - .getEntry(ConfigurationOptions.COMPONENT, - ConfigurationOptions.WRITE_PIPELINE_ADDR, - InetSocketAddress.class); - - /* - * Configuration properties for this HAJournal. - */ - final Properties properties = JiniClient.getProperties( - HAJournal.class.getName(), config); - - // Force the writePipelineAddr into the Properties. - properties.put(HAJournal.Options.WRITE_PIPELINE_ADDR, - writePipelineAddr); - - /* - * Zookeeper quorum. - */ - { - final List<ACL> acl = zkClientConfig.acl; - final String zoohosts = zkClientConfig.servers; - final int sessionTimeout = zkClientConfig.sessionTimeout; - - zka = new ZooKeeperAccessor(zoohosts, sessionTimeout); - - if (!zka.awaitZookeeperConnected(10, TimeUnit.SECONDS)) { - - throw new RuntimeException("Could not connect to zk"); - - } - - if (log.isInfoEnabled()) { - log.info("Connected to zookeeper"); - } - - /* - * Ensure key znodes exist. - */ - try { - zka.getZookeeper() - .create(zkClientConfig.zroot, - new byte[] {/* data */}, acl, - CreateMode.PERSISTENT); - } catch (NodeExistsException ex) { - // ignore. - } - try { - zka.getZookeeper() - .create(logicalServiceZPathPrefix, - new byte[] {/* data */}, acl, - CreateMode.PERSISTENT); - } catch (NodeExistsException ex) { - // ignore. - } - try { - zka.getZookeeper() - .create(logicalServiceZPath, - new byte[] {/* data */}, acl, - CreateMode.PERSISTENT); - } catch (NodeExistsException ex) { - // ignore. - } - - quorum = new ZKQuorumImpl<HAGlue, QuorumService<HAGlue>>( - replicationFactor, zka, acl); - } - -// // The HAJournal. -// this.journal = new HAJournal(properties, quorum); - - } - -// TODO executor for events received in the watcher thread. -// singleThreadExecutor = new LatchedExecutor( -// journal.getExecutorService(), 1/* nparallel */); - -// // our external interface. -// haGlueService = journal.newHAGlue(serviceUUID); -// -// // wrap the external interface, exposing administrative functions. -// final AdministrableHAGlueService administrableService = new AdministrableHAGlueService( -// this, haGlueService); -// -// // return that wrapped interface. -// return administrableService; - - } - - protected void startUp() throws IOException { - - if (log.isInfoEnabled()) - log.info("Starting server."); - - getQuorum().addListener(new QuorumListener() { - - @Override - public void notify(final QuorumEvent e) { - if (log.isTraceEnabled()) - log.trace(e); // TODO LOG @ TRACE - } - }); - - // Setup the quorum client (aka quorum service). - quorumMember = new MyQuorumMember(logicalServiceZPath, serviceId); - - } - - protected void backup() throws Exception { - - final long token = quorumMember.getQuorum().token(); - - quorumMember.getQuorum().assertQuorum(token); - - quorumMember.new BackupTask(token).call(); - - } - - /** - * - * A randomly generated {@link UUID} that this utility uses to identify - * itself. - */ - protected UUID getServiceId() { - return serviceId; - } - - protected Quorum<?,?> getQuorum() { - return quorum; - } - - private class MyQuorumMember extends AbstractQuorumMember<HAPipelineGlue> { - - private final QuorumPipelineImpl<HAPipelineGlue> pipelineImpl = new QuorumPipelineImpl<HAPipelineGlue>(this) { - - @Override - protected void handleReplicatedWrite(final IHASyncRequest req, - final IHAWriteMessage msg, final ByteBuffer data) - throws Exception { - - MyQuorumMember.this.handleReplicatedWrite(req, msg, data); - - } - - @Override - public UUID getStoreUUID() { - throw new UnsupportedOperationException(); - } - - @Override - public long getLastCommitTime() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public long getLastCommitCounter() { - // TODO Auto-generated method stub - return 0; - } - - @Override - public void logWriteCacheBlock(IHAWriteMessage msg, ByteBuffer data) - throws IOException { - // TODO Auto-generated method stub - - } - - @Override - public void logRootBlock(boolean isJoinedService,IRootBlockView rootBlock) - throws IOException { - // TODO Auto-generated method stub - - } - - @Override - public void purgeHALogs() { - // TODO Auto-generated method stub - - } - -// @Override -// public long getLastCommitTime() { -// -// return MyQuorumMember.this.getLastCommitTime(); -// -// } -// -// @Override -// public long getLastCommitCounter() { -// -// return MyQuorumMember.this.getLastCommitCounter(); -// -// } -// -// @Override -// public void logWriteCacheBlock(final IHAWriteMessage msg, -// final ByteBuffer data) throws IOException { -// -// MyQuorumMember.this.logWriteCacheBlock(msg, data); -// -// } -// -// @Override -// public void logRootBlock(final IRootBlockView rootBlock) -// throws IOException { -// -// MyQuorumMember.this.logRootBlock(rootBlock); -// -// } -// -// @Override -// public void purgeHALogs(final boolean includeCurrent) { -// -// MyQuorumMember.this.purgeHALogs(includeCurrent); -// -// } - - }; - - /** - * The local implementation of the {@link Remote} interface. - */ - private final HAPipelineGlue service; - -// /** -// * Simple service registrar. -// */ -// private final MockServiceRegistrar<S> registrar; - - /** - * The last lastCommitTime value around which a consensus was achieved - * and initially -1L, but this is cleared to -1L each time the consensus - * is lost. - */ - protected volatile long lastConsensusValue = -1L; - - /** - * The downstream service in the write pipeline. - */ - protected volatile UUID downStreamId = null; - - private volatile ExecutorService executorService = null; - - protected MyQuorumMember(final String logicalServiceId, - final UUID serviceId) throws IOException { - - super(logicalServiceId, serviceId); - - service = new MyQuorumService(); - - /* - * Delegates. - */ - - addListener(this.pipelineImpl); - - } - - @Override - public void start(final Quorum<?, ?> quorum) { - if (executorService == null) - executorService = Executors - .newSingleThreadExecutor(DaemonThreadFactory - .defaultThreadFactory()); - super.start(quorum); - } - - @Override - public void terminate() { - super.terminate(); - if(executorService!=null) { - executorService.shutdownNow(); - executorService = null; - } - } - - public Executor getExecutor() { - return executorService; - } - -// /** -// * Factory for the local service implementation object. -// */ -// abstract S newService(); - - public HAPipelineGlue getService() { - return service; - } - - /** - * Resolve an {@link HAGlue} object from its Service UUID. - */ - @Override - public HAGlue getService(final UUID serviceId) { - -// final HAJournalDiscoveryClient discoveryClient = -// .getDiscoveryClient(); - - final ServiceItem serviceItem = discoveryClient - .getServiceItem(serviceId); - - if (serviceItem == null) { - - // Not found (per the API). - throw new QuorumException("Service not found: uuid=" - + serviceId); - - } - - @SuppressWarnings("unchecked") - final HAGlue service = (HAGlue) serviceItem.service; - - return service; - - } - - /** - * {@inheritDoc} - * - * Overridden to save the <i>lastCommitTime</i> on - * {@link #lastConsensusValue}. - */ - @Override - public void consensus(long lastCommitTime) { - super.consensus(lastCommitTime); - this.lastConsensusValue = lastCommitTime; - } - - @Override - public void lostConsensus() { - super.lostConsensus(); - this.lastConsensusValue = -1L; - } - - /** - * {@inheritDoc} - * - * Overridden to save the current downstream service {@link UUID} on - * {@link #downStreamId} - */ - public void pipelineChange(final UUID oldDownStreamId, - final UUID newDownStreamId) { - super.pipelineChange(oldDownStreamId, newDownStreamId); - this.downStreamId = newDownStreamId; - } - - /** - * {@inheritDoc} - * - * Overridden to clear the {@link #downStreamId}. - */ - public void pipelineRemove() { - super.pipelineRemove(); - this.downStreamId = null; - } - - /** - * @see HAPipelineGlue - */ - protected void handleReplicatedWrite(IHASyncRequest req, - IHAWriteMessage msg, ByteBuffer data) throws Exception { - - // FIXME handle replicated writes! - - } - - /** - * Mock service class. - */ - class MyQuorumService implements HAPipelineGlue { - - private final InetSocketAddress addrSelf; - - public MyQuorumService() throws IOException { - this.addrSelf = new InetSocketAddress(getPort(0)); - } - - public InetSocketAddress getWritePipelineAddr() { - return addrSelf; - } - - /** - * @todo This is not fully general purpose since it is not strictly - * forbidden that the service's lastCommitTime could change, e.g., - * due to explicit intervention, and hence be updated across this - * operation. The real implemention should be a little more - * sophisticated. - */ - public Future<Void> moveToEndOfPipeline() throws IOException { - final FutureTask<Void> ft = new FutureTask<Void>(new Runnable() { - public void run() { - - // note the current vote (if any). - final Long lastCommitTime = getQuorum().getCastVote( - getServiceId()); - - if (isPipelineMember()) { - -// System.err -// .println("Will remove self from the pipeline: " -// + getServiceId()); - - getActor().pipelineRemove(); - -// System.err -// .println("Will add self back into the pipeline: " -// + getServiceId()); - - getActor().pipelineAdd(); - - if (lastCommitTime != null) { - -// System.err -// .println("Will cast our vote again: lastCommitTime=" -// + +lastCommitTime -// + ", " -// + getServiceId()); - - getActor().castVote(lastCommitTime); - - } - - } - } - }, null/* result */); - getExecutor().execute(ft); - return ft; - } - - @Override - public Future<Void> receiveAndReplicate(final IHASyncRequest req, - IHAWriteMessage msg) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public IHALogRootBlocksResponse getHALogRootBlocksForWriteSet( - IHALogRootBlocksRequest msg) throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public Future<Void> sendHALogForWriteSet(IHALogRequest msg) - throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public Future<IHASendStoreResponse> sendHAStore(IHARebuildRequest msg) - throws IOException { - throw new UnsupportedOperationException(); - } - - @Override - public IHAWriteSetStateResponse getHAWriteSetState( - IHAWriteSetStateRequest req) { - throw new UnsupportedOperationException(); - } - - } - - /** - * - * Create a full backup. - */ - private class BackupTask implements Callable<Void> { - - /** - * The quorum token in effect when we began the resync. - */ - private final long token; - - /** - * The quorum leader. This is fixed until the quorum breaks. - */ - private final HAGlue leader; - - public BackupTask(final long token) { - - // run while quorum is met. - this.token = token; - - // The leader for that met quorum (RMI interface). - leader = (... [truncated message content] |
From: <tho...@us...> - 2013-03-18 13:40:39
|
Revision: 7006 http://bigdata.svn.sourceforge.net/bigdata/?rev=7006&view=rev Author: thompsonbry Date: 2013-03-18 13:40:26 +0000 (Mon, 18 Mar 2013) Log Message: ----------- Continued progress towards HA snapshot/restore patterns. - AbstractServer, HAJournalServer: modified to log as well as use stdout for startup message since stdout messges not captured in log files for test suites. - HAJournal: stubbed out pattern for taking a snapshot. - SnapshotManager: modified snapshot pattern to return Future and provided a method to report the Future for a snapshot if one is running. - NSS: Added support for reporting on snapshot progress and requesting a snapshot to StatusServlet and HAStatusServletUtil. - AbstractJournal: added doLocalCommit() variant to support HARestore utility. - Added HARestoreUtility (untested). HA test suites are green (except for the 5 known failure points). Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/StatusServlet.java Added Paths: ----------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HARestore.java Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -5135,7 +5135,32 @@ } /** + * Local commit protocol (HA, offline). + * <p> + * Note: This is used to support RESTORE by replay of HALog files when + * the HAJournalServer is offline. + * + * TODO This method should be protected. If we move the HARestore class + * into this package, then it can be changed from public to protected or + * package private. + */ + final public void doLocalCommit(final IRootBlockView rootBlock) { + + doLocalCommit(null/* localService */, rootBlock); + + } + + /** * Local commit protocol (HA). + * + * @param localService + * For HA modes only. When non-<code>null</code>, this is used to + * identify whether the service is the leader. When the service + * is not the leader, we need to do some additional work to + * maintain the {@link IRWStrategy} allocators in synch at each + * commit point. + * @param rootBlock + * The new root block. */ protected void doLocalCommit(final QuorumService<HAGlue> localService, final IRootBlockView rootBlock) { @@ -5155,8 +5180,8 @@ // set the new root block. _rootBlock = rootBlock; - final boolean leader = localService.isLeader(rootBlock - .getQuorumToken()); + final boolean leader = localService == null ? false : localService + .isLeader(rootBlock.getQuorumToken()); if (!leader) { @@ -5167,7 +5192,7 @@ * be updating the allocators. */ - if (haLog.isInfoEnabled()) + if (haLog.isInfoEnabled() && localService != null) haLog.info("Reset from root block: serviceUUID=" + localService.getServiceId()); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/AbstractServer.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -1836,8 +1836,13 @@ if (runState.compareAndSet(RunState.Start, RunState.Running)) { - System.out.println("Service is running: class=" - + getClass().getName() + ", name=" + getServiceName()); + { + final String msg = "Service is running: class=" + + getClass().getName() + ", name=" + getServiceName(); + System.out.println(msg); + if (log.isInfoEnabled()) + log.info(msg); + } /* * Wait until the server is terminated. Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -25,10 +25,13 @@ import java.lang.ref.WeakReference; import java.util.Calendar; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import org.apache.log4j.Logger; +import com.bigdata.journal.IRootBlockView; + /** * Policy schedules a snapshot at the same time each day. A threshold is used to * skip the backup if the HALog delta is LTE a specified percentage of the size @@ -113,11 +116,24 @@ final HAJournal jnl = ref.get(); - if (jnl == null) + if (jnl == null) { + + // Journal reference has been cleared. return; + + } - jnl.getSnapshotManager().takeSnapshot(percentLogSize); + // Conditionally start a snapshot. + final Future<IRootBlockView> f = jnl.getSnapshotManager() + .takeSnapshot(percentLogSize); + if (f != null) { + + // Wait for the snapshot to complete. + f.get(); + + } + } catch (Throwable t) { log.error(t, t); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -311,6 +311,7 @@ { + // Note: Default is relative to the serviceDir. haLogDir = (File) config .getEntry( HAJournalServer.ConfigurationOptions.COMPONENT, @@ -549,7 +550,7 @@ * @throws ExecutionException * @throws InterruptedException */ - Future<IRootBlockView> takeSnapshotNow() throws Exception { + Future<IRootBlockView> takeSnapshotNow() { final FutureTask<IRootBlockView> ft = new FutureTaskMon<IRootBlockView>( new SnapshotTask()); @@ -563,6 +564,11 @@ /** * Take a snapshot. + * + * TODO If possible, move this code to the {@link SnapshotManager} class. + * Both the {@link SnapshotManager} and the {@link HARestore} classes could + * be moved into the {@link Journal} package (and the {@link HARestore} + * class renamed since it would then be usable without the HAJournalServer). */ private class SnapshotTask implements Callable<IRootBlockView> { @@ -576,6 +582,14 @@ if (!getQuorum().getClient().isJoinedMember(token)) { + /* + * Note: The service must be joined with a met quorum to take a + * snapshot. This is necessary in order to ensure that the + * snapshots are copies of a journal state that the quorum + * agrees on, otherwise we could later attempt to restore from + * an invalid state. + */ + throw new QuorumException("Service not joined with met quorum"); } @@ -599,12 +613,12 @@ final IRootBlockView currentRootBlock = RootBlockUtility .chooseRootBlock(rootBlocks[0], rootBlocks[1]); - // TODO It is a problem if this file exists and is not (logically) - // empty. + // TODO SNAPSHOT: It is a problem if this file exists and is not + // (logically) empty. final File file = getSnapshotManager().getSnapshotFile( currentRootBlock.getCommitCounter()); - // FIXME Modify to use GZip on outputStream. + // FIXME SNAPSHOT: Modify to use GZip on outputStream. IBufferAccess buf = null; RandomAccessFile raf = null; try { @@ -672,21 +686,31 @@ haLog.debug("Sending block: sequence=" + sequence + ", offset=" + offset + ", nbytes=" + nbytes); + if (!getQuorum().getClient().isJoinedMember(token)) { + /* + * Abort the snapshot if the service leaves the quorum + * or if the quorum breaks. + */ + throw new QuorumException( + "Snapshot aborted: service not joined with met quorum."); + } + if(true) { /* - * FIXME We have to actually read the block off of the - * backing store and then write it onto the file - * channel. + * FIXME SNAPSHOT: We have to actually read the block + * off of the backing store and then write it onto the + * file channel. * - * FIXME Make sure to write out empty root blocks first. + * FIXME SNAPSHOT: Make sure to write out empty root + * blocks first. * - * FIXME Skip over the root blocks before writing the - * data blocks. + * FIXME SNAPSHOT: Skip over the root blocks before + * writing the data blocks. * - * FIXME Write the root blocks afterwards, ideally with - * the checksum of the data blocks. + * FIXME SNAPSHOT: Write the root blocks afterwards, + * ideally with the checksum of the data blocks. * - * FIXME Add compression. + * FIXME SNAPSHOT: Add compression. */ throw new UnsupportedOperationException(); } @@ -706,6 +730,16 @@ } + /* + * FIXME SNAPSHOT: Lay down the root blocks. + */ + + if (!getQuorum().getClient().isJoinedMember(token)) { + // Verify before putting down the root blocks. + throw new QuorumException( + "Snapshot aborted: service not joined with met quorum."); + } + if (haLog.isInfoEnabled()) haLog.info("Sent store file: #blocks=" + sequence + ", #bytes=" + (fileExtent - headerSize)); Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -3291,8 +3291,12 @@ serviceURL = new URL("http", hostAddr, actualPort, ""/* file */) .toExternalForm(); - System.out.println("logicalServiceZPath: " + logicalServiceZPath); - System.out.println("serviceURL: " + serviceURL); + final String msg = "logicalServiceZPath: " + logicalServiceZPath + + "\n" + "serviceURL: " + serviceURL; + + System.out.println(msg); + if (log.isInfoEnabled()) + log.info(msg); } Added: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HARestore.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HARestore.java (rev 0) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HARestore.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -0,0 +1,540 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. 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.jini.ha; + +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.Properties; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import org.apache.log4j.Logger; + +import com.bigdata.ha.halog.HALogReader; +import com.bigdata.ha.halog.HALogWriter; +import com.bigdata.ha.halog.IHALogReader; +import com.bigdata.ha.msg.IHAWriteMessage; +import com.bigdata.io.DirectBufferPool; +import com.bigdata.io.IBufferAccess; +import com.bigdata.io.writecache.WriteCache; +import com.bigdata.journal.IHABufferStrategy; +import com.bigdata.journal.IRootBlockView; +import com.bigdata.journal.Journal; +import com.bigdata.journal.Options; + +/** + * Utility class may be used to apply HALog files to a {@link Journal}, rolling + * it forward to a specific commit point. + * + * @author <a href="mailto:tho...@us...">Bryan Thompson</a> + * + * FIXME HARestore : write test suite. + */ +public class HARestore { + + /** + * Logger for HA events. + */ + private static final Logger haLog = Logger.getLogger("com.bigdata.haLog"); + + private final Journal journal; + private final File haLogDir; + + public HARestore(final Journal journal, final File haLogDir) { + + if (journal == null) + throw new IllegalArgumentException(); + + if (haLogDir == null) + throw new IllegalArgumentException(); + + this.journal = journal; + + this.haLogDir = haLogDir; + + } + + /** + * Apply HALog files, rolling the {@link Journal} forward one commit point + * at a time. + * + * @param listCommitPoints + * When <code>true</code>, the HALog files are visited and their + * root blocks are validated and logged, but nothing is applied + * to the {@link Journal}. + * @param haltingCommitCounter + * The last commit counter that will be applied (halting point + * for the restore). + * + * @throws IOException + * @throws InterruptedException + */ + public void restore(final boolean listCommitPoints, + final long haltingCommitCounter) throws IOException, + InterruptedException { + + // The initial root block on the journal + final IRootBlockView initialRootBlock; + + /* + * Dump out the journal's root block. + */ + + initialRootBlock = journal.getRootBlockView(); + + if (haLog.isInfoEnabled()) + haLog.info("JOURNAL: file=" + journal.getFile() + + ", commitCounter=" + initialRootBlock.getCommitCounter() + + ", initialRootBlock=" + initialRootBlock); + + /* + * Now roll through the HALog files for the commit points starting with + * the first commit point not found on the Journal. + */ + int nfound = 0; + long totalBytes = 0L; + for (long cc = initialRootBlock.getCommitCounter();; cc++) { + + if (haltingCommitCounter != Long.MAX_VALUE + && cc > haltingCommitCounter) { + + /* + * Done. We have applied all desired HALog files. + */ + break; + + } + + final File logFile = new File(haLogDir, + HALogWriter.getHALogFileName(cc)); + + if (!logFile.exists()) { + + /* + * We have run out of HALog files. It is possible that there are + * HALog files for future commit points, but there is no HALog + * file for this commit point. + */ + break; + + } + + final IHALogReader logReader = new HALogReader(logFile); + + try { + + if (logReader.isEmpty()) { + + haLog.warn("Empty HALog: commitCounter=" + cc); + + /* + * We can not continue once we hit an empty HALog file. + * + * Note: An HALog file is empty until the closing root block + * is written onto the file. Thus, an empty HALog file can + * exist when the server was shutdown abruptly. Since the + * commit point was never applied, the HALog file is empty + * and we can not roll the database any further forward. + */ + break; + + } + + // dump closing root block. + final IRootBlockView lrb = logReader.getClosingRootBlock(); + + if (haLog.isInfoEnabled()) + haLog.info("HALog: commitCounter=" + lrb.getCommitCounter() + + ", closingRootBlock=" + lrb); + + // Verify HALog root block consistent with journal. + assertRootBlocksConsistent(journal, lrb); + + nfound++; + + totalBytes += logFile.length(); + + if (!listCommitPoints) { + + /* + * Apply HALog and go through a local commit. + * + * See HAJournalServer.RestoreTask() which already does + * this. + */ + applyHALog(logReader); + + journal.doLocalCommit(logReader.getClosingRootBlock()); + + } + + } finally { + + logReader.close(); + + } + + } // next commit point + + if (haLog.isInfoEnabled()) + haLog.info("HALogDir: nfound=" + + nfound + + ", totalBytes=" + + totalBytes + + (haltingCommitCounter == Long.MAX_VALUE ? "" + : ", haltingCommitCounter=" + haltingCommitCounter)); + + if (!listCommitPoints) { + + final IRootBlockView finalRootBlock = journal.getRootBlockView(); + + if (haLog.isInfoEnabled()) + haLog.info("JOURNAL: file=" + journal.getFile() + + ", commitCounter=" + + finalRootBlock.getCommitCounter() + + ", finalRootBlock=" + finalRootBlock); + + } + + } + + /** + * Apply the write set to the local journal. + * + * @param r + * The {@link IHALogReader} for the HALog file containing + * the write set. + * + * @throws IOException + * @throws InterruptedException + */ + private void applyHALog(final IHALogReader r) throws IOException, + InterruptedException { + + final IBufferAccess buf = DirectBufferPool.INSTANCE.acquire(); + + try { + + while (r.hasMoreBuffers()) { + + // get message and fill write cache buffer (unless WORM). + final IHAWriteMessage msg = r.processNextBuffer(buf + .buffer()); + + writeWriteCacheBlock(msg, buf.buffer()); + + } + + haLog.warn("Applied HALog: closingCommitCounter=" + + r.getClosingRootBlock().getCommitCounter()); + + } finally { + + buf.release(); + + } + } + + /** + * Write the raw {@link WriteCache} block onto the backing store. + */ + private void writeWriteCacheBlock(final IHAWriteMessage msg, + final ByteBuffer data) throws IOException, InterruptedException { + + setExtent(msg); + + /* + * Note: the ByteBuffer is owned by the HAReceiveService. This just + * wraps up the reference to the ByteBuffer with an interface that + * is also used by the WriteCache to control access to ByteBuffers + * allocated from the DirectBufferPool. However, release() is a NOP + * on this implementation since the ByteBuffer is owner by the + * HAReceiveService. + */ + + final IBufferAccess b = new IBufferAccess() { + + @Override + public void release(long timeout, TimeUnit unit) + throws InterruptedException { + // NOP + } + + @Override + public void release() throws InterruptedException { + // NOP + } + + @Override + public ByteBuffer buffer() { + return data; + } + }; + + ((IHABufferStrategy) journal.getBufferStrategy()) + .writeRawBuffer(msg, b); + + } + + /** + * Adjust the size on the disk of the local store to that given in the + * message. + * <p> + * Note: When historical messages are being replayed, the caller needs + * to decide whether the message should applied to the local store. If + * so, then the extent needs to be updated. If not, then the message + * should be ignored (it will already have been replicated to the next + * follower). + */ + private void setExtent(final IHAWriteMessage msg) throws IOException { + + try { + + ((IHABufferStrategy) journal.getBufferStrategy()) + .setExtentForLocalStore(msg.getFileExtent()); + + } catch (InterruptedException e) { + + throw new RuntimeException(e); + + } catch (RuntimeException t) { + + // Wrap with the HA message. + throw new RuntimeException("msg=" + msg + ": " + t, t); + + } + + } + + /** + * Apply HALog file(s) to the journal. Each HALog file represents a single + * native transaction on the database and will advance the journal by one + * commit point. The journal will go through local commit protocol as each + * HALog is applied. HALogs will be applied starting with the first commit + * point GT the current commit point on the journal. You may optionally + * specify a stopping criteria, e.g., the last commit point that you wish to + * restore. If no stopping criteria is specified, then all HALog files in + * the specified directory will be applied and the journal will be rolled + * forward to the most recent transaction. The HALog files are not removed, + * making this process safe. + * + * @param args + * <code>[options] journalFile haLogDir</code><br> + * where <code>journalFile</code> is the name of the journal file<br> + * where <code>haLogDir</code> is the name of a directory + * containing zero or more HALog files<br> + * where <code>options</code> are any of: + * <dl> + * <dt>-l</dt> + * <dd>List available commit points, but do not apply them. This + * option provides information about the current commit point on + * the journal and the commit points available in the HALog + * files.</dd> + * <dt>-h commitCounter</dt> + * <dd>The last commit counter that will be applied (halting + * point for restore).</dd> + * </dl> + * + * @return <code>0</code> iff the operation was fully successful. + * + * @throws Exception + * if the {@link UUID}s or other critical metadata of the + * journal and the HALogs differ. + * @throws Exception + * if an error occcur when reading an HALog or writing on the + * journal. + */ + public static void main(final String[] args) { + + if (args.length == 0) { + + usage(args); + + System.exit(1); + + } + + int i = 0; + + boolean listCommitPoints = false; + + // Defaults to Long.MAX_VALUE. + long haltingCommitCounter = Long.MAX_VALUE; + + for (; i < args.length; i++) { + + String arg = args[i]; + + if (!arg.startsWith("-")) { + + // End of options. + break; + + } + + if (arg.equals("-l")) { + + listCommitPoints = true; + + } + + else if (arg.equals("-h")) { + + haltingCommitCounter = Long.parseLong(args[i + 1]); + + } + + else + throw new RuntimeException("Unknown argument: " + arg); + + } + + if (i != args.length - 1) { + + usage(args); + + System.exit(1); + + } + + // Journal file. + final File journalFile = new File(args[i++]); + + // HALogDir. + final File haLogDir = new File(args[i++]); + + // Validate journal file. + { + + System.out.println("Journal File: " + journalFile); + + if (!journalFile.exists()) { + + System.err.println("No such file: " + journalFile); + + System.exit(1); + + } + + if (!journalFile.isFile()) { + + System.err.println("Not a regular file: " + journalFile); + + System.exit(1); + + } + + System.out.println("Length: " + journalFile.length()); + + System.out.println("Last Modified: " + + new Date(journalFile.lastModified())); + + } + + try { + + final Properties properties = new Properties(); + + { + + properties.setProperty(Options.FILE, journalFile.toString()); + + if (listCommitPoints) + properties.setProperty(Options.READ_ONLY, "" + true); + + // properties.setProperty(Options.BUFFER_MODE, + // BufferMode.Disk.toString()); + + } + + final Journal journal = new Journal(properties); + + try { + + final HARestore util = new HARestore(journal, haLogDir); + + util.restore(listCommitPoints, haltingCommitCounter); + + } finally { + + journal.close(); + + } + + } catch (Throwable t) { + + t.printStackTrace(); + + System.exit(1); + + } + + } + + /** + * Verify that the HALog root block is consistent with the Journal's root + * block. + * + * @param jnl + * The journal. + * @param lrb + * The HALog's root block. + */ + private static void assertRootBlocksConsistent(final Journal jnl, + final IRootBlockView lrb) { + + if (jnl == null) + throw new IllegalArgumentException(); + + if (lrb == null) + throw new IllegalArgumentException(); + + // Current root block. + final IRootBlockView jrb = jnl.getRootBlockView(); + + if (!jrb.getUUID().equals(lrb.getUUID())) { + + throw new RuntimeException("UUID differs: journal=" + jrb + + ", log=" + lrb); + + } + + if (!jrb.getStoreType().equals(lrb.getStoreType())) { + + throw new RuntimeException("StoreType differs: journal=" + jrb + + ", log=" + lrb); + + } + + } + + private static void usage(final String[] args) { + + System.err.println("usage: (-l|-h commitPoint) <journalFile> haLogDir"); + + } + +} Modified: branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java =================================================================== --- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -1,3 +1,26 @@ +/** + +Copyright (C) SYSTAP, LLC 2006-2007. 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.jini.ha; import java.io.File; @@ -7,6 +30,9 @@ import java.nio.channels.FileChannel; import java.util.Formatter; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import net.jini.config.Configuration; import net.jini.config.ConfigurationException; @@ -64,6 +90,18 @@ * index MUST be synchronized on its object monitor. */ private final CommitTimeIndex snapshotIndex; + + /** + * Lock used to guard the decision to take a snapshot. + */ + private final Lock lock = new ReentrantLock(); + + /** + * The {@link Future} of the current snapshot (if any). + * <p> + * This field is guarded by the {@link #lock}. + */ + private Future<IRootBlockView> snapshotFuture = null; /** * Return the {@link ISnapshotPolicy}. @@ -114,6 +152,7 @@ // Note: This is the effective service directory. final File serviceDir = server.getServiceDir(); + // Note: Default is relative to the serviceDir. snapshotDir = (File) config .getEntry( HAJournalServer.ConfigurationOptions.COMPONENT, @@ -309,37 +348,94 @@ return true; } - + /** + * Return the {@link Future} of the current snapshot operation (if any). + * + * @return The {@link Future} of the current snapshot operation -or- + * <code>null</code> if there is no snapshot operation running. + */ + public Future<IRootBlockView> getSnapshotFuture() { + + lock.lock(); + + try { + + if (snapshotFuture != null) { + + if (!snapshotFuture.isDone()) { + + // Still running. + return snapshotFuture; + + } + + snapshotFuture = null; + + } + + return snapshotFuture; + + } finally { + + lock.unlock(); + + } + + } + + /** * Take a new snapshot. This is a NOP if a snapshot is already being made. * + * @return The {@link Future} if a snapshot is already being made -or- if a + * snapshot was started by the request and <code>null</code> if no + * snapshot will be taken in response to this request. + * * @throws Exception * @throws ExecutionException * @throws InterruptedException */ - // TODO Could return Future. More useful. - public boolean takeSnapshot(final int percentLogSize) - throws InterruptedException, ExecutionException, Exception { + public Future<IRootBlockView> takeSnapshot(final int percentLogSize) { - /* - * FIXME If already running, then return immediately. Use lock, etc. - * - * FIXME lock should also cause purge of snapshots to be deleted if we - * are in the middle of making a decision about whether or not to make a - * new snapshot. - */ + lock.lock(); + + try { - if (!isReadyToSnapshot(percentLogSize)) { + if (snapshotFuture != null) { - return false; + if (!snapshotFuture.isDone()) { + // Still running. + return snapshotFuture; + + } + + snapshotFuture = null; + + } + + /* + * FIXME lock should also cause purge of snapshots to be deleted if + * we are in the middle of making a decision about whether or not to + * make a new snapshot. + */ + + if (!isReadyToSnapshot(percentLogSize)) { + + // Pre-conditions are not met. + return null; + + } + + // Take the snapshot, return Future but save a reference. + return snapshotFuture = journal.takeSnapshotNow(); + + } finally { + + lock.unlock(); + } - // Take the snapshot. Wait for the Future. - journal.takeSnapshotNow().get(); - - return true; - } /** @@ -415,9 +511,26 @@ * snapshot. If the size(halogs) as a percentage of the size(journal) is LTE * the given [percentLogSize], then we return [false] to indicate that no * snapshot should be taken. + * <p> + * Note: The service must be joined with a met quorum to take a snapshot. + * This is checked here and also in HAJournal when we take the snapshot. + * This is necessary in order to ensure that the snapshots are copies of a + * journal state that the quorum agrees on, otherwise we could later attempt + * to restore from an invalid state. */ private boolean isReadyToSnapshot(final int percentLogSize) { + final long token = journal.getQuorum().token(); + + if (!journal.getQuorum().getClient().isJoinedMember(token)) { + + haLog.warn("Service not joined with met quorum."); + + // This service is not joined with a met quorum. + return false; + + } + final long snapshotCommitCounter = getMostRecentSnapshotCommitCounter(); /* Modified: branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java =================================================================== --- branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -36,8 +36,9 @@ import com.bigdata.ha.HAGlue; import com.bigdata.ha.QuorumService; import com.bigdata.ha.halog.IHALogReader; -import com.bigdata.journal.AbstractJournal; import com.bigdata.journal.IIndexManager; +import com.bigdata.journal.jini.ha.HAJournal; +import com.bigdata.journal.jini.ha.SnapshotManager; import com.bigdata.quorum.zk.ZKQuorumImpl; import com.bigdata.zookeeper.DumpZookeeper; @@ -76,14 +77,14 @@ * * @throws IOException */ - public void showQuorum(final HttpServletRequest req, + public void doGet(final HttpServletRequest req, final HttpServletResponse resp, final XMLBuilder.Node current) throws IOException { - if (!(indexManager instanceof AbstractJournal)) + if (!(indexManager instanceof HAJournal)) return; - final AbstractJournal journal = (AbstractJournal) indexManager; + final HAJournal journal = (HAJournal) indexManager; final ZKQuorumImpl<HAGlue, QuorumService<HAGlue>> quorum = (ZKQuorumImpl<HAGlue, QuorumService<HAGlue>>) journal .getQuorum(); @@ -135,8 +136,8 @@ { final File file = journal.getFile(); if (file != null) { - p.text("DataDir: path=" + file.getParent()) - .node("br").close(); + p.text("journal: file=" + file + ", nbytes=" + + journal.size()).node("br").close(); } } @@ -163,6 +164,71 @@ + nbytes + ", path=" + haLogDir).node("br") .close(); } + + /* + * Report #of files and bytes in the snapshot directory. + */ + { + final File snapshotDir = ((HAJournal) journal) + .getSnapshotManager().getSnapshotDir(); + final File[] a = snapshotDir.listFiles(new FilenameFilter() { + @Override + public boolean accept(File dir, String name) { + return name.endsWith(SnapshotManager.SNAPSHOT_EXT); + } + }); + int nfiles = 0; + long nbytes = 0L; + for (File file : a) { + nbytes += file.length(); + nfiles++; + } + p.text("SnapshotDir: nfiles=" + nfiles + ", nbytes=" + nbytes + + ", path=" + snapshotDir).node("br").close(); + } + + /* + * If requested, conditional start a snapshot. + */ + { + final String val = req.getParameter(StatusServlet.SNAPSHOT); + + if (val != null) { + + /* + * Attempt to interpret the parameter as a percentage + * (expressed as an integer). + * + * Note: The default threshold will trigger a snapshot + * regardless of the size of the journal and the #of HALog + * files. A non-default value of 100 will trigger the + * snapshot if the HALog files occupy as much space on the + * disk as the Journal. Other values may be used as + * appropriate. + */ + int percentLogSize = 0; + try { + percentLogSize = Integer.parseInt(val); + } catch (NumberFormatException ex) { + // ignore. + } + + ((HAJournal) journal).getSnapshotManager().takeSnapshot( + percentLogSize); + + } + + } + + /* + * Report if a snapshot is currently running. + */ + if (journal.getSnapshotManager().getSnapshotFuture() != null) { + + p.text("Snapshot running.").node("br").close(); + + } + p.close(); current.node("pre", quorum.toString()); Modified: branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/StatusServlet.java =================================================================== --- branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/StatusServlet.java 2013-03-18 13:22:04 UTC (rev 7005) +++ branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/StatusServlet.java 2013-03-18 13:40:26 UTC (rev 7006) @@ -147,6 +147,13 @@ static final String CANCEL_QUERY = "cancelQuery"; /** + * Request a snapshot of the journal (HA only). The snapshot will be written + * into the configured directory on the server. If a snapshot is already + * being taken then this is a NOP. + */ + static final String SNAPSHOT = "snapshot"; + + /** * Handles CANCEL requests (terminate a running query). */ @Override @@ -398,7 +405,7 @@ .isHighlyAvailable()) { new HAStatusServletUtil(getIndexManager()) - .showQuorum(req, resp, current); + .doGet(req, resp, current); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |