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

org.infinispan.quarkus.hibernate.cache.Sync Maven / Gradle / Ivy

package org.infinispan.quarkus.hibernate.cache;

import org.hibernate.cache.spi.CacheTransactionSynchronization;
import org.hibernate.cache.spi.RegionFactory;
import org.jboss.logging.Logger;

import java.util.Arrays;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;

final class Sync implements CacheTransactionSynchronization {
    private static final Logger log = Logger.getLogger(Sync.class);
    private final static boolean trace = log.isTraceEnabled();

    private final RegionFactory regionFactory;
    private long transactionStartTimestamp;
    // to save some allocations we're storing everything in a single array
    private Object[] tasks;
    private int index;

    Sync(RegionFactory regionFactory) {
        this.regionFactory = regionFactory;
        transactionStartTimestamp = regionFactory.nextTimestamp();
    }

    void registerBeforeCommit(CompletableFuture future) {
        add(future);
    }

    void registerAfterCommit(QueryResultsRegionImpl.PostTransactionQueryUpdate invocation) {
        add(invocation);
    }

    private void add(Object task) {
        if (trace) {
            log.tracef("Adding %08x %s", System.identityHashCode(task), task);
        }
        if (tasks == null) {
            tasks = new Object[4];
        } else if (index == tasks.length) {
            tasks = Arrays.copyOf(tasks, tasks.length << 1);
        }
        tasks[index++] = task;
    }

    @Override
    public long getCachingTimestamp() {
        return transactionStartTimestamp;
    }

    @Override
    public void transactionJoined() {
        transactionStartTimestamp = regionFactory.nextTimestamp();
    }

    @Override
    public void transactionCompleting() {
        if (trace) {
            int done = 0, notDone = 0;
            for (int i = 0; i < index; ++i) {
                Object task = tasks[i];
                if (task instanceof CompletableFuture) {
                    if (((CompletableFuture) task).isDone()) {
                        done++;
                    } else {
                        notDone++;
                    }
                }
            }
            log.tracef("%d tasks done, %d tasks not done yet", done, notDone);
        }
        int count = 0;
        for (int i = 0; i < index; ++i) {
            Object task = tasks[i];
            if (task instanceof CompletableFuture) {
                if (trace) {
                    log.tracef("Waiting for %08x %s", System.identityHashCode(task), task);
                }
                try {
                    ((CompletableFuture) task).join();
                } catch (CompletionException e) {
                    log.errorf(e, "Operation #%d scheduled to complete before transaction completion failed", i);
                }
                tasks[i] = null;
                ++count;
            } else {
                if (trace) {
                    log.tracef("Not waiting for %08x %s", System.identityHashCode(task), task);
                }
            }
        }
        if (trace) {
            log.tracef("Finished %d tasks before completion", count);
        }
    }

    @Override
    public void transactionCompleted(boolean successful) {
        if (!successful) {
            // When the transaction is rolled back transactionCompleting() is not called,
            // so we could have some completable futures waiting.
            transactionCompleting();
        }
        int invoked = 0, waiting = 0;
        for (int i = 0; i < index; ++i) {
            Object invocation = tasks[i];
            if (invocation == null) {
                continue;
            }
            try {
                tasks[i] = ((QueryResultsRegionImpl.PostTransactionQueryUpdate) invocation).apply(successful);
            } catch (Exception e) {
                log.errorf(e, "Operation #%d scheduled after transaction completion failed (transaction successful? %s)", i, successful);
                tasks[i] = null;
            }
            invoked++;
        }
        for (int i = 0; i < index; ++i) {
            CompletableFuture cf = (CompletableFuture) tasks[i];
            if (cf != null) {
                try {
                    cf.join();
                } catch (Exception e) {
                    log.errorf(e, "Operation #%d scheduled after transaction completion failed (transaction successful? %s)", i, successful);
                }
                waiting++;
            }
        }
        if (trace) {
            log.tracef("Invoked %d tasks after completion, %d are synchronous.", invoked, waiting);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy