diff --git a/.github/actions/install-mvnd/action.yml b/.github/actions/install-mvnd/action.yml index 9769860c218..a0dc3bdf1ff 100644 --- a/.github/actions/install-mvnd/action.yml +++ b/.github/actions/install-mvnd/action.yml @@ -48,7 +48,7 @@ runs: - name: Cache mvnd if: inputs.cache == 'true' id: cache-mvnd - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ${{ inputs.install-path }}/${{ env.MVND_NAME }}.zip diff --git a/.github/workflows/ci-deploy.yml b/.github/workflows/ci-deploy.yml index 713f690259f..7b01ad93dfa 100644 --- a/.github/workflows/ci-deploy.yml +++ b/.github/workflows/ci-deploy.yml @@ -13,7 +13,7 @@ jobs: - name: Set up JDK 8 uses: actions/setup-java@v4 with: - distribution: temurin + distribution: liberica java-version: '8' - name: Make buildkit default uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index 5c79eca5d33..d92c2a71b5e 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -13,7 +13,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: - distribution: temurin + distribution: liberica java-version: ${{ env.DEV_JDK }} cache: 'maven' - run: mvn -V -B license:check @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: - distribution: temurin + distribution: liberica java-version: ${{ env.DEV_JDK }} cache: 'maven' - name: OWASP dependency check @@ -40,26 +40,20 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macOS-latest] jvm: ['8'] - exclude: - - os: macOS-latest - jvm: '8' - include: - - os: macOS-latest - jvm: '11' runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - name: Set up JDK uses: actions/setup-java@v4 with: - distribution: temurin + distribution: liberica java-version: ${{ matrix.jvm }} cache: 'maven' - name: Install Maven Daemon id: install-mvnd uses: ./.github/actions/install-mvnd with: - version: '1.0.1' + version: '1.0.2' file-version-suffix: '' cache: 'true' - name: Maven Build diff --git a/.github/workflows/ci-xqts.yml b/.github/workflows/ci-xqts.yml index 5ac15c77617..f7a42da20f5 100644 --- a/.github/workflows/ci-xqts.yml +++ b/.github/workflows/ci-xqts.yml @@ -12,7 +12,7 @@ jobs: - name: Set up JDK 8 uses: actions/setup-java@v4 with: - distribution: temurin + distribution: liberica java-version: '8' - name: Cache Maven packages uses: actions/cache@v4 diff --git a/exist-core/pom.xml b/exist-core/pom.xml index 2664c859842..a8266cbb4f1 100644 --- a/exist-core/pom.xml +++ b/exist-core/pom.xml @@ -1097,7 +1097,7 @@ The BaseX Team. The original license statement is also included below.]]> - @{jacocoArgLine} -Dfile.encoding=${project.build.sourceEncoding} + @{jacocoArgLine} -Dfile.encoding=${project.build.sourceEncoding} -Dexist.recovery.progressbar.hide=true ${project.basedir}/../exist-jetty-config/target/classes/org/exist/jetty ${project.build.testOutputDirectory}/conf.xml diff --git a/exist-core/src/main/java/org/exist/plugin/PluginsManagerImpl.java b/exist-core/src/main/java/org/exist/plugin/PluginsManagerImpl.java index 94d57e4a079..3dbbbbd3f58 100644 --- a/exist-core/src/main/java/org/exist/plugin/PluginsManagerImpl.java +++ b/exist-core/src/main/java/org/exist/plugin/PluginsManagerImpl.java @@ -241,7 +241,7 @@ public void addPlugin(final String className) { // NOTE: must set interrupted flag Thread.currentThread().interrupt(); } - LOG.error(e); + LOG.warn(e); } } diff --git a/exist-core/src/main/java/org/exist/storage/recovery/RecoveryManager.java b/exist-core/src/main/java/org/exist/storage/recovery/RecoveryManager.java index 99b074d685a..1822c9e0439 100644 --- a/exist-core/src/main/java/org/exist/storage/recovery/RecoveryManager.java +++ b/exist-core/src/main/java/org/exist/storage/recovery/RecoveryManager.java @@ -45,6 +45,8 @@ import com.evolvedbinary.j8fu.function.SupplierE; import org.exist.util.sanity.SanityCheck; +import javax.annotation.Nullable; + /** * Database recovery. This class is used once during startup to check * if the database is in a consistent state. If not, the class attempts to recover @@ -59,11 +61,13 @@ public class RecoveryManager { private final DBBroker broker; private final JournalRecoveryAccessor journalRecovery; private final boolean restartOnError; + private final boolean hideProgressBar; public RecoveryManager(final DBBroker broker, final JournalManager journalManager, final boolean restartOnError) { this.broker = broker; this.journalRecovery = journalManager.getRecoveryAccessor(this); this.restartOnError = restartOnError; + this.hideProgressBar = Boolean.getBoolean("exist.recovery.progressbar.hide"); } /** @@ -120,10 +124,10 @@ public boolean recover() throws LogException { Lsn lastLsn = Lsn.LSN_INVALID; Loggable next; try { - final ProgressBar progress = new ProgressBar("Scanning journal ", FileUtils.sizeQuietly(last)); + final long lastSize = FileUtils.sizeQuietly(last); + @Nullable final ProgressBar scanProgressBar = hideProgressBar ? null : new ProgressBar("Scanning journal ", lastSize); while ((next = reader.nextEntry()) != null) { // LOG.debug(next.dump()); - progress.set(next.getLsn().getOffset()); if (next.getLogType() == LogEntryTypes.TXN_START) { // new transaction starts: add it to the transactions table txnsStarted.put(next.getTransactionId(), next); @@ -135,6 +139,14 @@ public boolean recover() throws LogException { lastCheckpoint = (Checkpoint) next; } lastLsn = next.getLsn(); + + if (scanProgressBar != null) { + scanProgressBar.set(next.getLsn().getOffset()); + } + } + + if (scanProgressBar != null) { + scanProgressBar.set(lastSize); // 100% } } catch (final LogException e) { if (LOG.isDebugEnabled()) { @@ -146,7 +158,7 @@ public boolean recover() throws LogException { // if the last checkpoint record is not the last record in the file // we need a recovery. if ((lastCheckpoint == null || !lastCheckpoint.getLsn().equals(lastLsn)) && - txnsStarted.size() > 0) { + !txnsStarted.isEmpty()) { LOG.info("Dirty transactions: {}", txnsStarted.size()); // starting recovery: reposition the log reader to the last checkpoint if (lastCheckpoint == null) { @@ -250,10 +262,11 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader if (LOG.isInfoEnabled()) { LOG.info("First pass: redoing {} transactions...", txnCount);} - final ProgressBar progress = new ProgressBar("Redo ", FileUtils.sizeQuietly(last)); Loggable next = null; int redoCnt = 0; try { + final long lastSize = FileUtils.sizeQuietly(last); + @Nullable final ProgressBar redoProgressBar = hideProgressBar ? null : new ProgressBar("Redo ", lastSize); while ((next = reader.nextEntry()) != null) { SanityCheck.ASSERT(next.getLogType() != LogEntryTypes.CHECKPOINT, "Found a checkpoint during recovery run! This should not ever happen."); @@ -271,9 +284,19 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader // LOG.debug("Redo: " + next.dump()); // redo the log entry next.redo(); - progress.set(next.getLsn().getOffset()); - if (next.getLsn().equals(lastLsn)) - {break;} // last readable entry reached. Stop here. + + if (redoProgressBar != null) { + redoProgressBar.set(next.getLsn().getOffset()); + } + + if (next.getLsn().equals(lastLsn)) { + // last readable entry reached. Stop here. + break; + } + } + + if (redoProgressBar != null) { + redoProgressBar.set(lastSize); // 100% done } } catch (final Exception e) { LOG.error("Exception caught while redoing transactions. Aborting recovery to avoid possible damage. " + @@ -291,16 +314,19 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader { LOG.info("Second pass: undoing dirty transactions. Uncommitted transactions: {}", runningTxns.size());} // see if there are uncommitted transactions pending - if (runningTxns.size() > 0) { + if (!runningTxns.isEmpty()) { // do a reverse scan of the log, undoing all uncommitted transactions try { - while((next = reader.previousEntry()) != null) { + final long lastSize = FileUtils.sizeQuietly(last); + final ProgressBar undoProgressBar = hideProgressBar ? null : new ProgressBar("Undo ", lastSize); + while ((next = reader.previousEntry()) != null) { if (next.getLogType() == LogEntryTypes.TXN_START) { if (runningTxns.get(next.getTransactionId()) != null) { runningTxns.remove(next.getTransactionId()); - if (runningTxns.size() == 0) + if (runningTxns.isEmpty()) { // all dirty transactions undone - {break;} + break; + } } } else if (next.getLogType() == LogEntryTypes.TXN_COMMIT) { // ignore already committed transaction @@ -314,6 +340,14 @@ private void doRecovery(final int txnCount, final Path last, final JournalReader // LOG.debug("Undo: " + next.dump()); next.undo(); } + + if (undoProgressBar != null) { + undoProgressBar.set(lastSize - next.getLsn().getOffset()); + } + } + + if (undoProgressBar != null) { + undoProgressBar.set(lastSize); // 100% done } } catch (final Exception e) { LOG.warn("Exception caught while undoing dirty transactions. Remaining transactions to be undone: {}. Aborting recovery to avoid possible damage. Before starting again, make sure to run a check via the emergency export tool.", runningTxns.size(), e);