From: <tho...@us...> - 2013-04-04 21:34:17
|
Revision: 7035 http://bigdata.svn.sourceforge.net/bigdata/?rev=7035&view=rev Author: thompsonbry Date: 2013-04-04 21:34:01 +0000 (Thu, 04 Apr 2013) Log Message: ----------- Continued work on HA Backup. Test suite all green except for "join during live load" and the new test for the HA restore policy. In addition, there are some new tests to be written, which I have outlined below. - Write unit test to verify that A+B take a snapshot of the empty journal. The snapshot should not exist on either service until both are running and the quorum meets. - Write unit test to verify that C snapshots the journal when it enters RunMet after resynchronizing from A+B. (This can just be start A+B, await quorum meet, then start C. C will resync from the leader. The snapshot should be taken when resync is done and we enter RunMet.) - Write unit test to verify that C snapshots the journal when it is rebuilding from the A+B. The leader must not have the HALogs on hand to trigger a REBUILD rather than a RESYNC. E.g., delete the log files and snapshots on the leader by hand. C should snapshot the journal when the REBUILD and RESYNC are done and it enters RunMet. - Write test to verify that a rebuild triggered while a snapshot is running will cancel the running snapshot. This is necessary since we must overwrite the root blocks. Start A+B+C. Load a bunch of data. Request a snapshot on C. Write on leader. Modified Paths: -------------- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.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/DumpJournal.java branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java branches/READ_CACHE/bigdata/src/resources/logging/log4j-dev.properties branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 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/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/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/NoSnapshotPolicy.java branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java 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/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/TestAll.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 branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3SnapshotPolicy.java 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/TestHAJournalServerGlobalWriteLock.java branches/READ_CACHE/bigdata-sails/src/java/com/bigdata/rdf/sail/webapp/HAStatusServletUtil.java branches/READ_CACHE/src/resources/HAJournal/HAJournal.config Added Paths: ----------- branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/AbstractHA3BackupTestCase.java branches/READ_CACHE/bigdata-jini/src/test/com/bigdata/journal/jini/ha/TestHA3RestorePolicy.java Removed Paths: ------------- branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/NoRestorePolicy.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-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumPipeline.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -180,14 +180,8 @@ * goes through a commit point in which the quorum is fully met. At that * 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. + * <p> + * Note: The open HALog file is NOT removed by this method. */ void purgeHALogs(); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/ha/QuorumService.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -123,4 +123,22 @@ void installRootBlocks(final IRootBlockView rootBlock0, final IRootBlockView rootBlock1); + /** + * Callback method. + * + * @param token + * The token on which the service joined a met quorum. + * @param commitCounter + * The commitCounter for the local service. + * @param isLeader + * <code>true</code> iff the local service is the quorum leader. + */ + /* + * I added this in but wound up not needed it. Do not use without good + * justification. + */ + @Deprecated + void didMeet(final long token, final long commitCounter, + final boolean isLeader); + } Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/AbstractJournal.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -4905,9 +4905,16 @@ } + // This quorum member. + final QuorumService<HAGlue> localService = quorum.getClient(); + /* * Both a meet and a break require an exclusive write lock. */ + final boolean isLeader; + final boolean isFollower; + final long localCommitCounter; + final WriteLock lock = _fieldReadWriteLock.writeLock(); lock.lock(); @@ -4936,6 +4943,9 @@ * widthdrawn. That is currently done by QuorumWatcherBase. So, * we have to wait until we observe that to cast a new vote. */ + + localCommitCounter = -1; + isLeader = isFollower = false; haReadyToken = Quorum.NO_QUORUM; // volatile write. @@ -4947,14 +4957,16 @@ quorumToken = newValue; - // This quorum member. - final QuorumService<HAGlue> localService = quorum.getClient(); - boolean installedRBs = false; + localCommitCounter = _rootBlock.getCommitCounter(); + if (localService.isFollower(quorumToken)) { - if (_rootBlock.getCommitCounter() == 0L) { + isLeader = false; + isFollower = true; + + if (localCommitCounter == 0L) { /* * Take the root blocks from the quorum leader and use @@ -5003,11 +5015,17 @@ } else if (localService.isLeader(quorumToken)) { + isLeader = true; + isFollower = false; + // ready as leader. tmp = newValue; } else { + isLeader = false; + isFollower = false; + // Not ready. tmp = Quorum.NO_QUORUM; @@ -5027,7 +5045,7 @@ doLocalAbort(); } - + this.haReadyToken = tmp; // volatile write. haReadyCondition.signalAll(); // signal ALL. @@ -5043,7 +5061,13 @@ lock.unlock(); } + + if (isLeader || isFollower) { + localService.didMeet(newValue, localCommitCounter, isLeader); + + } + } private final Condition haReadyCondition = _fieldReadWriteLock.writeLock().newCondition(); private volatile long haReadyToken = Quorum.NO_QUORUM; @@ -5192,6 +5216,14 @@ throw new IllegalArgumentException(); if (rootBlock1.isRootBlock0()) throw new IllegalArgumentException(); +// if (rootBlock0.getCommitCounter() != 0L) +// throw new IllegalArgumentException(); +// if (rootBlock1.getCommitCounter() != 0L) +// throw new IllegalArgumentException(); + if (!rootBlock0.getStoreType().equals(rootBlock1.getStoreType())) + throw new IllegalArgumentException(); + if (!rootBlock0.getUUID().equals(rootBlock1.getUUID())) + throw new IllegalArgumentException(); // if (_rootBlock.getCommitCounter() != 0) { // Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DumpJournal.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DumpJournal.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/DumpJournal.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -155,6 +155,8 @@ boolean showTuples = false; + boolean alternateRootBlock = false; + final List<Long> addrs = new LinkedList<Long>(); for(; i<args.length; i++) { @@ -197,7 +199,13 @@ showTuples = true; } - + + else if(arg.equals("-alternateRootBlock")) { + + alternateRootBlock = true; + + } + else if(arg.equals("-addr")) { addrs.add(Long.valueOf(args[i + 1])); @@ -254,6 +262,10 @@ properties.setProperty(Options.READ_ONLY, "" + true); + if (alternateRootBlock) + properties.setProperty(Options.ALTERNATE_ROOT_BLOCK, + "" + true); + properties.setProperty(Options.BUFFER_MODE, BufferMode.Disk.toString()); Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/journal/RootBlockView.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -627,6 +627,46 @@ return new RootBlockView(rootBlock0, asReadOnlyBuffer(), checker); } + + /** + * {@inheritDoc} + * <p> + * Overridden to implement the hash code as the hash code of the data in the + * backing {@link ByteBuffer}. The {@link IRootBlockView} is immutable. The + * hash code is computed lazily. Once computed, the hash code is NOT + * recomputed for the same {@link IRootBlockView}. + */ + @Override + public int hashCode() { + if (hash == 0) { + /* + * Computed once (unless there is a data race, in which case it + * might be computed more than once but it will be consistent). + */ + hash = buf.asReadOnlyBuffer().hashCode(); + } + return hash; + } + + private volatile int hash = 0; + + /** + * {@inheritDoc} + * + * Overriden to implement equality based on the data in the + * {@link IRootBlockView}. + */ + @Override + public boolean equals(final Object o) { + if (this == o) + return true; + if (!(o instanceof IRootBlockView)) + return false; + final IRootBlockView o2 = (IRootBlockView) o; + if (!buf.asReadOnlyBuffer().equals(o2.asReadOnlyBuffer())) + return false; + return true; + } /** * Create a new read-only view from the supplied buffer. Modified: branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java =================================================================== --- branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/java/com/bigdata/rwstore/RWStore.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -2616,6 +2616,17 @@ */ m_writeCacheService.close(); m_writeCacheService = newWriteCache(); + } else if (m_writeCacheService != null) { + /* + * Note: We DO NOT need to reset() the WriteCacheService. If a + * record was already flushed to the disk, then it is on the + * disk and clearing the record from the cache will not change + * that. If the record has not yet been flushed to the disk, + * then we already cleared it from the WCS when we reset the + * FixedAllocators (above). + */ +// m_writeCacheService.reset(); +// m_writeCacheService.setExtent(convertAddr(m_fileSize)); } /* * Discard any writes on the delete blocks. Those deletes MUST NOT Modified: branches/READ_CACHE/bigdata/src/resources/logging/log4j-dev.properties =================================================================== --- branches/READ_CACHE/bigdata/src/resources/logging/log4j-dev.properties 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/resources/logging/log4j-dev.properties 2013-04-04 21:34:01 UTC (rev 7035) @@ -269,13 +269,13 @@ # Normal data loader (single threaded). log4j.logger.com.bigdata.rdf.store.DataLoader=INFO -#log4j.logger.com.bigdata.ha=ALL -#log4j.logger.com.bigdata.txLog=ALL -#log4j.logger.com.bigdata.haLog=ALL +log4j.logger.com.bigdata.ha=ALL +log4j.logger.com.bigdata.txLog=ALL +log4j.logger.com.bigdata.haLog=ALL #log4j.logger.com.bigdata.rwstore=ALL -#log4j.logger.com.bigdata.journal=ALL +log4j.logger.com.bigdata.journal=INFO #log4j.logger.com.bigdata.journal.AbstractBufferStrategy=ALL -#log4j.logger.com.bigdata.journal.jini.ha=ALL +log4j.logger.com.bigdata.journal.jini.ha=ALL #log4j.logger.com.bigdata.service.jini.lookup=ALL #log4j.logger.com.bigdata.quorum=ALL #log4j.logger.com.bigdata.quorum.zk=ALL @@ -285,7 +285,7 @@ log4j.logger.benchmark.bigdata.TestBSBM=INFO # Test suite logger. -#log4j.logger.junit=INFO +log4j.logger.junit=INFO #log4j.logger.junit=DEBUG log4j.logger.com.bigdata.btree.AbstractBTreeTestCase=INFO 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-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata/src/test/com/bigdata/journal/ha/AbstractHAJournalTestCase.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -472,6 +472,12 @@ } @Override + public void didMeet(final long token, final long commitCounter, + final boolean isLeader) { + throw new UnsupportedOperationException(); + } + + @Override public File getServiceDir() { throw new UnsupportedOperationException(); } Modified: 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 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/CommitTimeIndex.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -143,8 +143,6 @@ if(index == -1) { // No match. - log.warn("Not found: " + timestamp); - return null; } @@ -229,13 +227,13 @@ pos = -(pos+1); - if(pos == 0) { + if (pos == 0) { // No entry is less than or equal to this timestamp. return -1; - + } - + pos--; return pos; @@ -290,41 +288,164 @@ super.insert(key, BytesUtil.getBytes(rootBlock.asReadOnlyBuffer())); } + + /** + * Find and return the {@link IRootBlockView} for the oldest snapshot (if + * any). + * + * @return That {@link IRootBlockView} -or- <code>null</code> if there are + * no snapshots. + */ + public IRootBlockView getOldestSnapshot() { + + synchronized (this) { + + if (getEntryCount() == 0L) { + + // Empty index. + return null; + + } + + // Lookup first tuple in index. + @SuppressWarnings("unchecked") + final ITuple<IRootBlockView> t = valueAt(0L, getLookupTuple()); + + final IRootBlockView rb = t.getObject(); + + return rb; + + } + + } /** - * Find the commit counter for the most recent snapshot (if any). + * Find the {@link IRootBlockView} for the most recent snapshot (if any). * - * @return That commit counter -or- ZERO (0L) if there are no snapshots. + * @return That {@link IRootBlockView} -or- <code>null</code> if there are + * no snapshots. */ - public long getMostRecentSnapshotCommitCounter() { + public IRootBlockView getNewestSnapshot() { - final long snapshotCommitCounter; + /* + * Note: This could also be written using valueAt(nentries). + */ synchronized (this) { @SuppressWarnings("unchecked") - final ITupleIterator<IRootBlockView> itr = - rangeIterator(null/* fromKey */, null/* toKey */, - 1/* capacity */, IRangeQuery.DEFAULT - | IRangeQuery.REVERSE/* flags */, null/* filter */); + final ITupleIterator<IRootBlockView> itr = rangeIterator( + null/* fromKey */, null/* toKey */, 1/* capacity */, + IRangeQuery.DEFAULT | IRangeQuery.REVERSE/* flags */, null/* filter */); - if (itr.hasNext()) { + if (!itr.hasNext()) { + return null; + + } + + final ITuple<IRootBlockView> t = itr.next(); + + final IRootBlockView rb = t.getObject(); + + return rb; + + } + + } + + /** + * Find the oldest snapshot whose commit counter is LTE the specified commit + * counter. + * + * @return The {@link IRootBlockView} for that snapshot -or- + * <code>null</code> if there is no such snapshot. + * + * @throws IllegalArgumentException + * if <code>commitCounter LT ZERO (0)</code> + */ + public IRootBlockView findByCommitCounter(final long commitCounter) { + + if (commitCounter < 0L) + throw new IllegalArgumentException(); + + synchronized (this) { + + // Reverse scan. + @SuppressWarnings("unchecked") + final ITupleIterator<IRootBlockView> itr = rangeIterator( + null/* fromKey */, null/* toKey */, 0/* capacity */, + IRangeQuery.DEFAULT | IRangeQuery.REVERSE/* flags */, null/* filter */); + + while (itr.hasNext()) { + final ITuple<IRootBlockView> t = itr.next(); - - final IRootBlockView rootBlock = t.getObject(); - snapshotCommitCounter = rootBlock.getCommitCounter(); + final IRootBlockView rb = t.getObject(); - } else { + if (rb.getCommitCounter() <= commitCounter) { - snapshotCommitCounter = 0L; + // First snapshot LTE that commit counter. + return rb; + } + } + return null; + } + + } + + /** + * Return the snapshot that is associated with the specified ordinal index + * (origin ZERO) counting backwards from the most recent snapshot (0) + * towards the earliest snapshot (nsnapshots-1). + * <p> + * Note: The effective index is given by <code>(entryCount-1)-index</code>. + * If the effective index is LT ZERO (0) then there is no such snapshot and + * this method will return <code>null</code>. + * + * @param index + * The index. + * + * @return The {@link IRootBlockView} for that snapshot -or- + * <code>null</code> if there is no such snapshot. + * + * @throws IllegalArgumentException + * if <code>index LT ZERO (0)</code> + */ + public IRootBlockView getSnapshotByReverseIndex(final int index) { - return snapshotCommitCounter; + if (index < 0) + throw new IllegalArgumentException(); + synchronized (this) { + + final long entryCount = getEntryCount(); + + if (entryCount > Integer.MAX_VALUE) + throw new AssertionError(); + + final int effectiveIndex = ((int) entryCount - 1) - index; + + if (effectiveIndex < 0) { + + // No such snapshot. + return null; + + } + + @SuppressWarnings("unchecked") + final ITuple<IRootBlockView> t = valueAt(effectiveIndex, + getLookupTuple()); + + final IRootBlockView rb = t.getObject(); + + return rb; + + } + } /** Modified: 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 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultRestorePolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -25,61 +25,193 @@ import java.util.concurrent.TimeUnit; +import org.apache.log4j.Logger; + import com.bigdata.journal.IRootBlockView; /** - * The default restore policy. + * The default restore policy. This policy supports three different criteria for + * deciding when snapshots (aka full backups) and HALogs (aka write ahead log + * files for each commit point aka incremental backups) may be purged. + * <dl> + * <dt>minSnapshotAgeMillis</dt> + * <dd>The minimum age of a snapshot before it may be deleted.</dd> + * <dt>minSnapshots</dt> + * <dd>The minimum number of snapshot files (aka full backups) that must be + * retained.</dd> + * <dt>minRestorePoints</dt> + * <dd>The minimum number of commit points that must be restorable from backup. + * This explicitly controls the number of HALog files that will be retained. It + * also implicitly controls the number of snapshot files that will be retained + * since an HALog file will pin the newest snapshot whose commit counter is LTE + * to the the closing commit counter on that HALog file.</dd> + * </dl> * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> */ public class DefaultRestorePolicy implements IRestorePolicy { - private final long millis; + private static final Logger log = Logger + .getLogger(DefaultRestorePolicy.class); + + /** + * The default minimum age of a snapshot before it may be purged (7 days). + */ + public static final long DEFAULT_MIN_SNAPSHOT_AGE_MILLIS = TimeUnit.DAYS + .toMillis(7); /** + * The default minimum #of snapshots which must be retained ( + * {@value #DEFAULT_MIN_SNAPSHOTS}). + */ + public static final int DEFAULT_MIN_SNAPSHOTS = 1; + + /** + * The default minimum #of commit points that must be retained ( + * {@value #DEFAULT_MIN_RESTORE_POINTS}). + */ + public static final int DEFAULT_MIN_RESTORE_POINTS = 0; + + /** + * The minimum age of a snapshot before it may be purged. + */ + private final long minSnapshotAgeMillis; + + /** + * The minimum #of snapshots that must be retained. + */ + private final int minSnapshots; + + /** + * The minimum #of restore points (HALogs) that must be retained. + */ + private final int minRestorePoints; + + @Override + public String toString() { + + return DefaultRestorePolicy.class.getSimpleName()// + + "{minSnapshotAge=" + minSnapshotAgeMillis + "ms"// + + ",minSnapshots=" + minSnapshots // + + ",minRestorePoints=" + minRestorePoints // + + "}"; + + } + + /** * The default is to keep local backups on hand for 7 days. */ public DefaultRestorePolicy() { - this(TimeUnit.DAYS.toMillis(7)); - + this(DEFAULT_MIN_SNAPSHOT_AGE_MILLIS, DEFAULT_MIN_SNAPSHOTS, + DEFAULT_MIN_RESTORE_POINTS); + } /** - * Create a policy that will keep local backups on hand for the specified - * number of milliseconds. + * Create a policy that determines when local backups may be purged. The + * policy will retain local backups unless all of the criteria are + * satisified. * - * @param millis - * The #of milliseconds of state that can be restored from local - * backups. + * @param minSnapshotAgeMillis + * The minimum age of a snapshot (in milliseconds) before it may + * be purged. */ - public DefaultRestorePolicy(final long millis) { - - if (millis < 0) - throw new IllegalArgumentException(); + public DefaultRestorePolicy(final long minSnapshotAgeMillis) { - this.millis = millis; - + this(minSnapshotAgeMillis, DEFAULT_MIN_SNAPSHOTS, + DEFAULT_MIN_RESTORE_POINTS); + } /** + * Create a policy that determines when local backups may be purged. The + * policy will retain local backups unless all of the criteria are + * satisified. + * + * @param minSnapshotAgeMillis + * The minimum age of a snapshot (in milliseconds) before it may + * be purged. + * @param minSnapshots + * The minimum number of snapshots (aka full backups) that must + * be retained locally. + * @param minRestorePoints + * The minimum number of restore points (aka HALog files) that + * must be retained locally. If an HALog is pinned by this + * parameter, then the oldest snapshot LTE the commit counter of + * that HALog is also pinned, as are all HALog files GTE the + * snapshot and LT the HALog. + */ + public DefaultRestorePolicy(final long minSnapshotAgeMillis, + final int minSnapshots, final int minRestorePoints) { + + if (minSnapshotAgeMillis < 0) + throw new IllegalArgumentException( + "minSnapshotAgeMillis must be GTE ZERO (0), not " + + minSnapshotAgeMillis); + + if (minSnapshots < 1) + throw new IllegalArgumentException( + "minSnapshots must be GTE ONE (1), not " + minSnapshots); + + if (minRestorePoints < 0) + throw new IllegalArgumentException( + "minRestorePoints must be GTE ZERO (0), not " + + minRestorePoints); + + this.minSnapshotAgeMillis = minSnapshotAgeMillis; + + this.minSnapshots = minSnapshots; + + this.minRestorePoints = minRestorePoints; + + } + + /** * 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. + * is the #of milliseconds specified by the constructor for this policy. */ - @Override - public long getEarliestRestorableCommitPoint(final HAJournal jnl) { + private long getEarliestRestorableCommitCounterByAge(final HAJournal jnl, + final long commitCounterOnJournal) { final long now = System.currentTimeMillis(); - - final long then = now - millis; + final long then = now - minSnapshotAgeMillis; + final IRootBlockView rootBlock = jnl.getSnapshotManager().find(then); if (rootBlock == null) { // There are no snapshots. + return commitCounterOnJournal; + + } + + return rootBlock.getCommitCounter(); + + } + + /** + * This finds the snapshot that is <i>minSnapshots</i> back and returns its + * commit counter. If there are fewer than <i>minSnapshots</i>, then this + * returns ZERO (0). + */ + private long getEarliestRestorableCommitCounterBySnapshots( + final HAJournal jnl, final long commitCounterOnJournal) { + + if (minSnapshots == 0) { + + return commitCounterOnJournal; + + } + + final IRootBlockView rootBlock = jnl.getSnapshotManager() + .getSnapshotByReverseIndex(minSnapshots); + + if (rootBlock == null) { + + // There are fewer than minSnapshots snapshots. return 0L; } @@ -88,4 +220,80 @@ } + /** + * Find the oldest snapshot that is at least <i>minRestorePoints</i> old and + * returns its commit counter. If there is no such snapshot, then this + * returns ZERO (0). + */ + private long getEarliestRestorableCommitCounterByHALogs( + final HAJournal jnl, final long commitCounterOnJournal) { + + // The commit point that is [minRestorePoints] old. + final long desiredCommitCounter = commitCounterOnJournal + - minRestorePoints; + + if (desiredCommitCounter <= 0) { + + // There are fewer than this many commit points on the journal. + return 0L; + + } + + // Find the oldest snapshot LTE that commitCounter. + final IRootBlockView rootBlock = jnl.getSnapshotManager() + .findByCommitCounter(desiredCommitCounter); + + if (rootBlock == null) { + + return commitCounterOnJournal; + + } + + return rootBlock.getCommitCounter(); + + } + + /** + * {@inheritDoc} + * <p> + * Note: We use three different criteria here. Of necessity, this decision + * can not be atomic. Therefore, it is possible for new snapshots and HALogs + * to be created while we are concurrently evaluating those criteria. + * However, this concurrency can never result in fewer files being retained + * than are required by this policy. + */ + @Override + public long getEarliestRestorableCommitPoint(final HAJournal jnl) { + + // Current commit point on the journal. + final long commitCounterOnJournal = jnl.getRootBlockView() + .getCommitCounter(); + + final long commitCounterByAge = getEarliestRestorableCommitCounterByAge( + jnl, commitCounterOnJournal); + + final long commitCounterBySnapshots = getEarliestRestorableCommitCounterBySnapshots( + jnl, commitCounterOnJournal); + + final long commitCounterByHALogs = getEarliestRestorableCommitCounterByHALogs( + jnl, commitCounterOnJournal); + + final long ret = Math.min(commitCounterByAge, + Math.min(commitCounterBySnapshots, commitCounterByHALogs)); + + if (log.isInfoEnabled()) { + + log.info("policy=" + this + ", commitCounterOnJournal=" + + commitCounterOnJournal + ", commitCounterByAge=" + + commitCounterByAge + ", commitCounterBySnapshots=" + + commitCounterBySnapshots + ", commitCounterByHALogs=" + + commitCounterByHALogs + + ", effectiveCommitCounterReported=" + ret); + + } + + return ret; + + } + } 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-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/DefaultSnapshotPolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -25,6 +25,7 @@ import java.lang.ref.WeakReference; import java.util.Calendar; +import java.util.Formatter; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -47,6 +48,24 @@ final private int timeOfDay; final private int percentLogSize; + + @Override + public String toString() { + + final StringBuilder sb = new StringBuilder(); + + final Formatter f = new Formatter(sb); + + f.format("%04d", timeOfDay); + f.flush(); + f.close(); + + final String todStr = sb.toString(); + + return DefaultSnapshotPolicy.class.getSimpleName() + "{timeOfDay=" + + todStr + ", percentLogSize=" + percentLogSize + "%}"; + + } /** * The default policy wakes up at <code>0200</code> and takes a snapshot if Modified: 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 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ForeverRestorePolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -40,7 +40,7 @@ * This policy always returns ZERO to prevent backups from being released. */ @Override - public long getEarliestRestorableCommitPoint(HAJournal jnl) { + public long getEarliestRestorableCommitPoint(final HAJournal jnl) { return 0; 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-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournal.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -414,6 +414,36 @@ super.setQuorumToken(newValue); + if (newValue == Quorum.NO_QUORUM) { + + /* + * If there is a running snapshot, then cancel it since the quorum + * has broken. + * + * Note: The snapshot task will automatically terminate if it + * observes a quorum break or similar event. This is just being + * proactive. + * + * TODO Lift into HAJournalServer.quorumBreak() handler? + * + * TODO This will not be called if the quorum remains met but the + * local service leaves the quorum. However, we should still cancel + * a running snapshot if that occurs. + */ + + final Future<IHASnapshotResponse> ft = getSnapshotManager() + .getSnapshotFuture(); + + if (ft != null && !ft.isDone()) { + + haLog.info("Canceling snapshot."); + + ft.cancel(true/* mayInterruptIfRunning */); + + } + + } + } /** 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-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/HAJournalServer.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -264,6 +264,26 @@ ISnapshotPolicy DEFAULT_SNAPSHOT_POLICY = new DefaultSnapshotPolicy(); +// /** +// * <strong>TEST SUITE OPTION ONLY!</strong> +// * <p> +// * By default, a snapshot will be taken the first time the quorum meets +// * for each service. This provide the initial restore point, which +// * corresponds to an empty {@link HAJournal} with the correct root +// * blocks for the quorum. +// * <p> +// * This option MAY be used to suppress this behavior. This is used by +// * the test suite to avoid the creation of the initial snapshot. In +// * combination with an {@link DefaultRestorePolicy} which specifies +// * <code>minRestorePoints:=0</code>, this has the effect that we do not +// * hold onto HALog files (other than the current HALog file) until a +// * snapshot has been taken. The test suites control when snapshots are +// * taken and are thus able to test a variety of backup scenarios. +// */ +// String SNAPSHOT_ON_FIRST_MEET = "snapshotOnFirstMeet"; +// +// boolean DEFAULT_SNAPSHOT_ON_FIRST_MEET = true; + /** * The policy identifies the first commit point whose backups MUST NOT * be released. The policy may be based on the age of the commit point, @@ -1227,7 +1247,15 @@ final long token = getQuorum().token(); if (getQuorum().isQuorumFullyMet(token)) { - + /* + * TODO Even though the quorum is fully met, we should wait + * until we have a positive indication from the leader that + * it is "ha ready" before purging the HA logs and aging put + * snapshots. The leader might need to explicitly schedule + * this operation against the joined services and the + * services should then verify that the quorum is fully met + * before they actually age out the HALogs and snapshots. + */ purgeHALogs(); } @@ -1462,6 +1490,16 @@ } // validation of pre-conditions. + /* + * Conditionally take a snapshot of the journal iff there is no + * existing snapshot. The journal may or may not be empty, but + * we do not have any existing snapshots and we need to have one + * to serve as a restore point. The service MUST be joined with + * a met quorum in order to take a snapshot. + */ + + journal.getSnapshotManager().takeInitialSnapshot(); + // Block until this run state gets interrupted. blockInterruptably(); @@ -1687,10 +1725,17 @@ * Note: We MUST NOT install the local root blocks unless both * this service and the leader at at commitCounter ZERO(0L). */ + // Wait for the new root blocks. awaitJournalToken(token); { /* + * Get rid of any existing backups. They will not be + * consistent with the rebuild. + */ + deleteBackups(); + + /* * The current root block on the leader (We want to get some * immutatable metadata from the leader's root block). */ @@ -1723,6 +1768,12 @@ */ installRootBlocks(rbu.rootBlock0, rbu.rootBlock1); + // Note: Snapshot requires joined with met quorum. +// /* +// * Take a snapshot. +// */ +// journal.getSnapshotManager().takeInitialSnapshot(); + } /* @@ -1981,6 +2032,12 @@ openRootBlock.asRootBlock(true/* rootBlock0 */), openRootBlock.asRootBlock(false/* rootBlock0 */)); + // Note: snapshot requires joined with met quorum. +// /* +// * Take a snapshot. +// */ +// journal.getSnapshotManager().takeInitialSnapshot(); + } // Make sure we have the correct HALogWriter open. @@ -2923,20 +2980,20 @@ .getSnapshotManager().getRestorePolicy() .getEarliestRestorableCommitPoint(journal); - if (earliestRestorableCommitPoint == Long.MAX_VALUE) { + /* + * Release snapshots and HALog files no longer required by the + * restore policy. + * + * Note: The current HALog is NOT deleted. + */ - // Do not retain HALogs (other than the current one). - deleteHALogs(Long.MAX_VALUE); - - } else { + // Delete snapshots, returning commit counter of the oldest + // retained snapshot. + final long earliestRetainedSnapshotLastCommitCounter = deleteSnapshots(earliestRestorableCommitPoint); - // Release HALogs no longer required by the restore policy. - final long earliestRetainedSnapshotLastCommitCounter = deleteSnapshots(earliestRestorableCommitPoint); + // Delete HALogs not retained by that snapshot. + deleteHALogs(earliestRetainedSnapshotLastCommitCounter); - deleteHALogs(earliestRetainedSnapshotLastCommitCounter); - - } - } finally { logLock.unlock(); @@ -2946,10 +3003,38 @@ } /** + * We need to destroy the local backups if we do a REBUILD. Those files + * are no longer guaranteed to be consistent with the history of the + * journal. + */ + private void deleteBackups() { + + logLock.lock(); + + try { + + haLog.warn("Destroying local backups."); + + // Delete all snapshots. + deleteSnapshots(Long.MAX_VALUE); + + // Delete all HALogs (except the current one). + deleteHALogs(Long.MAX_VALUE); + + } finally { + + logLock.unlock(); + + } + + } + + /** * Delete snapshots that are no longer required. * <p> * Note: If ZERO (0) is passed into this method, then no snapshots will - * be deleted. + * be deleted. This is because the first possible commit counter is ONE + * (1). * * @param earliestRestorableCommitPoint * The earliest commit point that we need to be able to @@ -2962,6 +3047,8 @@ * List the snapshot files for this service. */ final File[] files; + // #of snapshot files found. Set during scan. + final AtomicLong nfound = new AtomicLong(); // Set to the commit counter of the earliest retained snapshot. final AtomicLong earliestRetainedSnapshotCommitCounter = new AtomicLong(Long.MAX_VALUE); final SnapshotManager snapshotManager = journal @@ -2995,6 +3082,9 @@ // Closing commitCounter for snapshot file. final long commitCounter = Long.parseLong(fileBaseName); + // Count all snapshot files. + nfound.incrementAndGet(); + if (commitCounter >= earliestRestorableCommitPoint) { /* * We need to retain this snapshot. @@ -3019,22 +3109,28 @@ int ndeleted = 0; long totalBytes = 0L; - if (files.length == 0) { + /* + * If people specify NoSnapshotPolicy then backup is in their hands. + * HALogs will not be retained beyond a fully met commit unless + * there is a snapshot against which they can be applied.. + */ + +// if (files.length == 0) { +// +// /* +// * Note: If there are no snapshots then we MUST retain ALL HALog +// * files. +// */ +// earliestRetainedSnapshotCommitCounter.set(0L); +// +// } else { - /* - * Note: If there are no snapshots then we MUST retain ALL HALog - * files. - */ - earliestRetainedSnapshotCommitCounter.set(0L); - - } else { - for (File file : files) { // #of bytes in that file. final long len = file.length(); - if (snapshotManager.removeSnapshot(file)) { + if (!snapshotManager.removeSnapshot(file)) { haLog.warn("COULD NOT DELETE FILE: " + file); @@ -3048,14 +3144,15 @@ } - } +// } - haLog.info("PURGED SNAPSHOTS: ndeleted=" + ndeleted - + ", totalBytes=" + totalBytes - + ", earliestRestorableCommitPoint=" - + earliestRestorableCommitPoint - + ", earliestRetainedSnapshotCommitCounter=" - + earliestRetainedSnapshotCommitCounter.get()); + if (haLog.isInfoEnabled()) + haLog.info("PURGED SNAPSHOTS: nfound=" + nfound + ", ndeleted=" + + ndeleted + ", totalBytes=" + totalBytes + + ", earliestRestorableCommitPoint=" + + earliestRestorableCommitPoint + + ", earliestRetainedSnapshotCommitCounter=" + + earliestRetainedSnapshotCommitCounter.get()); return earliestRetainedSnapshotCommitCounter.get(); @@ -3075,6 +3172,8 @@ * List the HALog files for this service. */ final File[] logFiles; + // #of HALog files found. Set during scan. + final AtomicLong nfound = new AtomicLong(); { final File currentLogFile = journal.getHALogWriter() @@ -3103,12 +3202,14 @@ return false; } + // track #of HALog files in the directory. + nfound.incrementAndGet(); + // filter out the current log file if (currentLogFile != null && name.equals(currentLogFileName)) { /* - * The caller requested that we NOT purge the - * current HALog, and this is it. + * This is the current HALog. We never purge it. */ return false; } @@ -3158,9 +3259,11 @@ } - haLog.info("PURGED LOGS: ndeleted=" + ndeleted + ", totalBytes=" - + totalBytes + ", earliestRetainedSnapshotCommitCounter=" - + earliestRetainedSnapshotCommitCounter); + if (haLog.isInfoEnabled()) + haLog.info("PURGED LOGS: nfound=" + nfound + ", ndeleted=" + + ndeleted + ", totalBytes=" + totalBytes + + ", earliestRetainedSnapshotCommitCounter=" + + earliestRetainedSnapshotCommitCounter); } @@ -3173,8 +3276,16 @@ } @Override + public void didMeet(final long token, final long commitCounter, + final boolean isLeader) { + // NOP + } + + @Override public File getServiceDir() { + return server.getServiceDir(); + } /** Modified: 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/IRestorePolicy.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/IRestorePolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -23,12 +23,21 @@ */ package com.bigdata.journal.jini.ha; - /** * The restore policy identifies the first commit point whose backups MUST NOT - * be released. The policy may be based on the age of the commit point, the - * number of intervening commit points, etc. A policy that always returns ZERO - * (0) will never release any backups. + * be released. Restore begins the most recent snapshot LTE the desired restore + * point and applies zero or more HALog files until the desired commit point has + * been restored. Therefore, the {@link IRestorePolicy} will pin the most recent + * snapshot LTE the computed earliest possible restore point and any HALog files + * for commit points GT that snapshot. A snapshot is taken automatically when + * the service first starts (and joins with a met quorum). This provides the + * initial full backup. Incremental logs are then retained until the next + * snapshot, at which point the {@link IRestorePolicy} may allow the older + * snapshot(s) and HALog files to be aged out. + * <p> + * The policy may be based on the age of the commit point, the number of + * intervening commit points, etc. A policy that always returns ZERO (0) will + * never release any backups. * * @author <a href="mailto:tho...@us...">Bryan Thompson</a> */ @@ -37,10 +46,29 @@ /** * Return the earlist commit point whose supporting backup files MUST NOT be * released in order to preseve the ability to restore that commit point - * from local backup files. + * from local backup files. The commit point is a commitCounter value. The + * first valid commit counter is ONE (1). A return value of ZERO (0) is + * therefore less than any possible commit point and will cause all commit + * points to be retained. The special value {@link Long#MAX_VALUE} may be + * used to indicate that NO commit points will be retained (it is greater + * than any possible commit counter). + * <p> + * Note: It is possible that new HALog files and new snapshots may appear + * concurrently during the evaluation of this method. This is unavoidable + * since both the leader and followers must evaluate this method in order to + * decide whether to release existing snapshot and HALog files. However, it + * is guaranteed that only one thread at a time on a given service will make + * the decision to release snapshots or HALog files. Since HALogs and + * snapshots may spring into existence concurrent with that decision, the + * {@link IRestorePolicy} can make decisions that retain slightly more + * information than would be required if the policy could have been + * evaluated atomicically with respect to the existing HALog files and + * snapshot files. This transient boundary condition can not result in fewer + * files being retained than are necessary to satisify the policy. * * @param jnl * The journal. + * * @return The earliest commit point whose supporting backup files must not * be released. */ Modified: 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/ISnapshotPolicy.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/ISnapshotPolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -45,5 +45,11 @@ * Initialize the policy. */ void init(HAJournal jnl); + + /** + * Return a human readable summary of the policy. + */ + @Override + String toString(); } Deleted: 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/NoRestorePolicy.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/NoRestorePolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -1,46 +0,0 @@ -/** - -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 does not preseve any backups. - * - * @author <a href="mailto:tho...@us...">Bryan Thompson</a> - */ -public class NoRestorePolicy implements IRestorePolicy { - - /** - * {@inheritDoc} - * <p> - * This policy always returns {@link Long#MAX_VALUE} to prevent backups from - * being retained. - */ - @Override - public long getEarliestRestorableCommitPoint(HAJournal jnl) { - - return Long.MAX_VALUE; - - } - -} Modified: 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/NoSnapshotPolicy.java 2013-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/NoSnapshotPolicy.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -34,5 +34,12 @@ public void init(HAJournal jnl) { // NOP } + + @Override + public String toString() { + return getClass().getSimpleName(); + + } + } 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-04-03 13:43:25 UTC (rev 7034) +++ branches/READ_CACHE/bigdata-jini/src/java/com/bigdata/journal/jini/ha/SnapshotManager.java 2013-04-04 21:34:01 UTC (rev 7035) @@ -57,6 +57,9 @@ import com.bigdata.btree.ITuple; import com.bigdata.btree.ITupleIterator; import com.bigdata.concurrent.FutureTaskMon; +import com.bigdata.concurrent.NamedLock; +import com.bigdata.ha.HAGlue; +import com.bigdata.ha.QuorumService; import com.bigdata.ha.halog.IHALogReader; import com.bigdata.ha.msg.HASnapshotResponse; import com.bigdata.ha.msg.IHASnapshotRequest; @@ -67,6 +70,7 @@ import com.bigdata.journal.ITx; import com.bigdata.journal.RootBlockUtility; import com.bigdata.journal.RootBlockView; +import com.bigdata.quorum.Quorum; import com.bigdata.quorum.QuorumException; import com.bigdata.rawstore.Bytes; import com.bigdata.util.ChecksumUtility; @@ -112,6 +116,11 @@ */ private final ISnapshotPolicy snapshotPolicy; +// /** +// * @see HAJournalServer.ConfigurationOptions#SNAPSHOT_ON_FIRST_MEET +// */ +// private final boolean snapshotOnFirstMeet; + /** * @see HAJournalServer.ConfigurationOptions#RESTORE_POLICY */ @@ -154,6 +163,18 @@ } +// /** +// * Return <code>true</code> iff the service will take a snapshot of the +// * empty journal when the service first joins with a met quorum. +// * +// * @see HAJournalServer.ConfigurationOptions#SNAPSHOT_ON_FIRST_MEET +// */ +// boolean isSnapshotOnFirstMeet() { +// +// return snapshotOnFirstMeet; +// +// } + /** * Return the {@link IRestorePolicy}. * @@ -216,6 +237,13 @@ ISnapshotPolicy.class,// HAJournalServer.ConfigurationOptions.DEFAULT_SNAPSHOT_POLICY); +// snapshotOnFirstMeet = !(snapshotPolicy instanceof NoSnapshotPolicy); +// snapshotOnFirstMeet = (Boolean) config.getEntry( +// HAJournalServer.ConfigurationOptions.COMPONENT, +// HAJournalServer.ConfigurationOptions.SNAPSHOT_ON_FIRST_MEET, +// Boolean.TYPE, +// HAJournalServer.ConfigurationOptions.DEFAULT_SNAPSHOT_ON_FIRST_MEET); + restorePolicy = (IRestorePolicy) config.getEntry( HAJournalServer.ConfigurationOptions.COMPONENT, HAJournalServer.ConfigurationOptions.RESTORE_POLICY, @@ -379,17 +407,17 @@ /* * Validate the snapshot. * - * TODO If the root blocks are bad, then this will throw an - * IOException and that will prevent the startup of the - * HAJournalServer. However, if we start up the server with a known - * bad snapshot *and* the snapshot is the earliest snapshot, then we - * can not restore commit points which depend on that earliest - * snapshot. + * TODO If the root blocks are bad, then this will throw an IOException + * and that will prevent the startup of the HAJournalServer. However, if + * we start up the ... [truncated message content] |