Skip to content

Commit

Permalink
Don't issue a checkpoint when finishing an index build if automatic c…
Browse files Browse the repository at this point in the history
…heckpointing isn't enabled. Also reorganize the checkpointing methods and eliminate redundant failure handling.
  • Loading branch information
broneill committed Aug 14, 2024
1 parent ff965c1 commit f0d08ab
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 68 deletions.
7 changes: 7 additions & 0 deletions src/main/java/org/cojen/tupl/core/Checkpointer.java
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,13 @@ private void suspend(int amt) {
}
}

/**
* Returns true if automatic checkpoints are currently enabled.
*/
boolean isEnabled() {
return mRateNanos >= 0 && isStarted() && !isSuspended();
}

/**
* Expected to only be implemented by the NodeGroup class.
*/
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/org/cojen/tupl/core/CoreDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,17 @@ public void rootSwap(Index a, Index b) throws IOException {
*/
public abstract EventListener eventListener();

/**
* Performs a checkpoint if automatic checkpoints are currently enabled.
*
* @return false if no checkpoint was performed
*/
public abstract boolean checkpointIfEnabled() throws IOException;

/**
* Called by Checkpointer task.
*/
abstract void checkpoint(long sizeThreshold, long delayThresholdNanos) throws IOException;
abstract boolean checkpoint(long sizeThreshold, long delayThresholdNanos) throws IOException;

/**
* Called by ReplController.
Expand Down
128 changes: 62 additions & 66 deletions src/main/java/org/cojen/tupl/core/LocalDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -2322,13 +2322,7 @@ public long preallocate(long bytes) throws IOException {
if (pageCount > 0) {
pageCount = mPageDb.allocatePages(pageCount);
if (pageCount > 0) {
try {
forceCheckpoint();
} catch (Throwable e) {
rethrowIfRecoverable(e);
closeQuietly(this, e);
throw e;
}
forceCheckpoint();
}
return pageCount * pageSize;
}
Expand Down Expand Up @@ -2678,13 +2672,62 @@ private void flush(int level) throws IOException {

@Override
public void checkpoint() throws IOException {
try {
checkpoint(0, 0);
} catch (Throwable e) {
rethrowIfRecoverable(e);
closeQuietly(this, e);
throw e;
checkpoint(0, 0, 0);
}

@Override
public boolean checkpointIfEnabled() throws IOException {
return mCheckpointer != null && mCheckpointer.isEnabled() && checkpoint(0, 0, 0);
}

@Override
boolean checkpoint(long sizeThreshold, long delayThresholdNanos) throws IOException {
return checkpoint(0, sizeThreshold, delayThresholdNanos);
}

private boolean forceCheckpoint() throws IOException {
return checkpoint(1, 0, 0);
}

/**
* @param force 0: no force, 1: force if not closed, -1: force even if closed
*/
private boolean checkpoint(int force, long sizeThreshold, long delayThresholdNanos)
throws IOException
{
while (!isClosed() && !isCacheOnly() && mCheckpointer != null) {
// Checkpoint lock ensures consistent state between page store and logs.
mCheckpointLock.lock();
try {
return doCheckpoint(force, sizeThreshold, delayThresholdNanos);
} catch (Throwable e) {
if (!isRecoverable(e)) {
// Panic.
closeQuietly(this, e);
throw e;
}

try {
cleanupMasterUndoLog();
} catch (Throwable e2) {
// Panic.
closeQuietly(this, e2);
suppress(e2, e);
throw e2;
}

// Retry and don't rethrow if leadership was lost.
if (!(e instanceof UnmodifiableReplicaException)) {
throw e;
}
} finally {
mCheckpointLock.unlock();
}

Thread.yield();
}

return false;
}

@Override
Expand Down Expand Up @@ -6145,55 +6188,6 @@ public EventListener eventListener() {
return mEventListener;
}

@Override
void checkpoint(long sizeThreshold, long delayThresholdNanos) throws IOException {
checkpoint(0, sizeThreshold, delayThresholdNanos);
}

private void forceCheckpoint() throws IOException {
checkpoint(1, 0, 0);
}

/**
* @param force 0: no force, 1: force if not closed, -1: force even if closed
*/
private void checkpoint(int force, long sizeThreshold, long delayThresholdNanos)
throws IOException
{
while (!isClosed() && !isCacheOnly() && mCheckpointer != null) {
// Checkpoint lock ensures consistent state between page store and logs.
mCheckpointLock.lock();
try {
doCheckpoint(force, sizeThreshold, delayThresholdNanos);
return;
} catch (Throwable e) {
if (!isRecoverable(e)) {
// Panic.
closeQuietly(this, e);
throw e;
}

try {
cleanupMasterUndoLog();
} catch (Throwable e2) {
// Panic.
closeQuietly(this, e2);
suppress(e2, e);
throw e2;
}

// Retry and don't rethrow if leadership was lost.
if (!(e instanceof UnmodifiableReplicaException)) {
throw e;
}
} finally {
mCheckpointLock.unlock();
}

Thread.yield();
}
}

/**
* Caller must hold mCheckpointLock.
*/
Expand Down Expand Up @@ -6299,11 +6293,11 @@ boolean waitForCommitted() {
*
* @param force 0: no force, 1: force if not closed, -1: force even if closed
*/
private void doCheckpoint(int force, long sizeThreshold, long delayThresholdNanos)
private boolean doCheckpoint(int force, long sizeThreshold, long delayThresholdNanos)
throws IOException
{
if (force >= 0 && isClosed()) {
return;
return false;
}

// Now's a good time to clean things up.
Expand Down Expand Up @@ -6334,7 +6328,7 @@ private void doCheckpoint(int force, long sizeThreshold, long delayThresholdNano
// Thresholds not met for a full checkpoint, but fully sync the redo log
// for durability. Don't reset mLastCheckpointStartNanos.
flush(2); // flush and sync metadata
return;
return false;
}

// Thresholds for a checkpoint are met, but it might not be necessary.
Expand Down Expand Up @@ -6375,7 +6369,7 @@ private void doCheckpoint(int force, long sizeThreshold, long delayThresholdNano
// Do reset mLastCheckpointStartNanos because thresholds were met.
flush(2); // flush and sync metadata
mLastCheckpointDurationNanos = 0;
return;
return false;
}
}

Expand Down Expand Up @@ -6583,6 +6577,8 @@ private void doCheckpoint(int force, long sizeThreshold, long delayThresholdNano
"Checkpoint completed in %1$1.3f seconds",
duration, TimeUnit.SECONDS);
}

return true;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/cojen/tupl/table/RowStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ void activateSecondaryIndex(IndexBackfill backfill, boolean success) throws IOEx
// With NO_REDO, need a checkpoint to ensure durability. If the database is closed
// before it finishes, the whole backfill process starts over when the database is
// later reopened.
mDatabase.checkpoint();
mDatabase.checkpointIfEnabled();
}
}

Expand Down

0 comments on commit f0d08ab

Please sign in to comment.