All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.persistit.TimestampAllocator Maven / Gradle / Ivy

There is a newer version: 3.3.0
Show newest version
/**
 * Copyright © 2011-2012 Akiban Technologies, Inc.  All rights reserved.
 * 
 * This program and the accompanying materials are made available
 * under the terms of the Eclipse Public License v1.0 which
 * accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * This program may also be available under different license terms.
 * For more information, see www.akiban.com or contact [email protected].
 * 
 * Contributors:
 * Akiban Technologies, Inc.
 */

package com.persistit;

import java.util.concurrent.atomic.AtomicLong;

import com.persistit.exception.PersistitInterruptedException;
import com.persistit.util.Util;

class TimestampAllocator {

    private final static int CHECKPOINT_TIMESTAMP_MARKER_INTERVAL = 100;

    private final static long UNAVAILABLE_CHECKPOINT_TIMESTAMP = -1;
    /**
     * Default interval in nanoseconds between checkpoints - two minutes.
     */
    private final AtomicLong _timestamp = new AtomicLong();

    private volatile long _checkpointTimestamp;

    public long updateTimestamp() {
        return _timestamp.incrementAndGet();
    }

    long bumpTimestamp(final long delta) {
        return _timestamp.addAndGet(delta);
    }

    public long updateTimestamp(final long timestamp) {
        _timestamp.incrementAndGet();
        while (true) {
            final long expected = _timestamp.get();
            if (expected < timestamp) {
                if (_timestamp.compareAndSet(expected, timestamp)) {
                    return timestamp;
                }
            } else {
                return expected;
            }
        }
    }

    /**
     * 

* Atomically allocate a new checkpoint timestamp. This method temporarily * marks the checkpoint timestamp field as "unavailable" until a new value * is computed. This prevents another thread executing * {@link Buffer#writePageOnCheckpoint(long)} from trusting the old * checkpoint timestamp while a new one is being allocated. *

*

* Here's the execution sequence to avoid: *

    *
  1. Let the initial checkpoint timestamp be c0. *
  2. Thread A (the checkpoint thread invoking this method) gets an updated * timestamp c1 which will become the new checkpoint timestamp.
  3. *
  4. Thread B (a thread attempting to modify a page that is already dirty * with timestamp t0) gets an updated timestamp t1 greater than c1
  5. *
  6. Thread B in writePageOnCheckpoint determines that t0 is larger than * the current checkpoint c0 (because the checkpoint timestamp field has not * been updated yet) and therefore continues on to further modify the page * without writing its state at t0.
  7. *
  8. Thread A now updates the checkpoint timestamp field to contain c1. * In this scenario the version of the page at t0 was never written to * the journal even though t0 < c1 and t1 > c1. This violates the recovery * safety requirement. *

    *

    * The solution is to stall the {@link #getProposedCheckpointTimestamp()} * method called by writePageOnCheckpoint before c1 is allocated until after * the checkpointTimestamp field containing c1 is visible. *

    * * @return the allocated timestamp */ long allocateCheckpointTimestamp() { /* * Add a gap to the timestamp counter - this is useful only for humans * trying to decipher timestamps in the journal - is not necessary for * correct function. */ bumpTimestamp(CHECKPOINT_TIMESTAMP_MARKER_INTERVAL); /* * Prevents Buffer#writePageOnCheckpoint from seeing the old checkpoint * while we are assigning the new one. The * getProposedCheckpointTimestamp method below spins until this has been * settled. */ _checkpointTimestamp = UNAVAILABLE_CHECKPOINT_TIMESTAMP; final long timestamp = updateTimestamp(); _checkpointTimestamp = timestamp; return timestamp; } public long getCurrentTimestamp() { return _timestamp.get(); } long getProposedCheckpointTimestamp() throws PersistitInterruptedException { long timestamp; /* * Spin until stable. This value must not be observed until set. */ for (int iterations = 0; (timestamp = _checkpointTimestamp) == UNAVAILABLE_CHECKPOINT_TIMESTAMP; iterations++) { if (iterations > 10) { Util.spinSleep(); } } return timestamp; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy