com.nimbusds.infinispan.persistence.sql.ExpiredEntryPagedReaper Maven / Gradle / Ivy
package com.nimbusds.infinispan.persistence.sql;
import com.codahale.metrics.Timer;
import com.nimbusds.infinispan.persistence.common.InfinispanEntry;
import net.jcip.annotations.ThreadSafe;
import org.infinispan.metadata.InternalMetadata;
import org.infinispan.persistence.spi.AdvancedCacheExpirationWriter;
import org.infinispan.persistence.spi.MarshallableEntryFactory;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.impl.DSL;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import static org.jooq.impl.DSL.table;
/**
* Expired entry reaper, utilises a paged key set seek strategy.
*/
@ThreadSafe
class ExpiredEntryPagedReaper extends ExpiredEntryReaper {
/**
* The page limit.
*/
private final int pageLimit;
/**
* Creates a new paged reaper for expired entries.
*
* @param mEntryFactory The Infinispan marshallable entry factory.
* @param dsl The DSL context.
* @param recordTransformer The SQL record transformer.
* @param recordWrapper The SQL record wrapper to use.
* @param pageLimit The SQL select query page limit.
* @param deleteTimer The SQL delete timer to use.
*/
public ExpiredEntryPagedReaper(final MarshallableEntryFactory mEntryFactory,
final DSLContext dsl,
final SQLRecordTransformer recordTransformer,
final Function recordWrapper,
final int pageLimit,
final Timer deleteTimer) {
super(mEntryFactory, dsl, recordTransformer, recordWrapper, deleteTimer);
assert pageLimit > 0;
this.pageLimit = pageLimit;
}
@Override
public void purgeWithEntryListener(final AdvancedCacheExpirationWriter.ExpirationPurgeListener purgeListener) {
// The entries for deletion
Queue> forDeletion = new LinkedList<>();
var numDeleted = new AtomicLong();
var lastRetrievedEntry = new AtomicReference>();
var numRetrieved = new AtomicLong();
// First SELECT with ORDER BY and LIMIT
dsl.select()
.from(table(recordTransformer.getTableName()))
.where(resolveExpiredCondition())
.orderBy(recordTransformer.getKeyColumnsForExpiredEntryReaper())
.limit(DSL.inline(pageLimit))
.stream()
.forEach(record -> {
RetrievedSQLRecord retrievedRecord = recordWrapper.apply(record);
numRetrieved.incrementAndGet();
InfinispanEntry infinispanEntry;
try {
infinispanEntry = recordTransformer.toInfinispanEntry(retrievedRecord);
} catch (Exception e) {
logIllegalRecordError(retrievedRecord);
return;
}
lastRetrievedEntry.set(infinispanEntry);
InternalMetadata metadata = infinispanEntry.getMetadata();
if (metadata != null && metadata.isExpired(System.currentTimeMillis())) {
// Add record for deletion
forDeletion.offer(infinispanEntry);
}
});
numDeleted.set(delete(forDeletion, purgeListener));
if (numRetrieved.get() < pageLimit) {
return;
}
// Continue with SELECTs using seek by key set
var numRetrievedInPage = new AtomicLong();
do {
numRetrievedInPage.set(0L);
final long now = System.currentTimeMillis();
dsl.select()
.from(table(recordTransformer.getTableName()))
.where(resolveExpiredCondition())
.orderBy(recordTransformer.getKeyColumnsForExpiredEntryReaper())
.seek(toVarArg(recordTransformer.getKeyValuesForExpiredEntryReaper(lastRetrievedEntry.get().getKey())))
.limit(DSL.inline(pageLimit))
.stream()
.forEach(record -> {
RetrievedSQLRecord retrievedRecord = recordWrapper.apply(record);
numRetrieved.incrementAndGet();
numRetrievedInPage.incrementAndGet();
InfinispanEntry infinispanEntry;
try {
infinispanEntry = recordTransformer.toInfinispanEntry(retrievedRecord);
} catch (Exception e) {
logIllegalRecordError(retrievedRecord);
return;
}
lastRetrievedEntry.set(infinispanEntry);
InternalMetadata metadata = infinispanEntry.getMetadata();
if (metadata != null && metadata.isExpired(now)) {
// Add record for deletion
forDeletion.offer(infinispanEntry);
}
});
numDeleted.addAndGet(delete(forDeletion, purgeListener));
} while (numRetrievedInPage.get() >= pageLimit);
Loggers.SQL_LOG.debug("[IS0128] SQL store: Purged {} expired out of {} {} cache entries with paging",
numDeleted, numRetrieved, recordTransformer.getTableName());
}
private long delete(final Queue> entries,
final AdvancedCacheExpirationWriter.ExpirationPurgeListener purgeListener) {
return delete(entries, en -> purgeListener.marshalledEntryPurged(toMarshallableEntry(en)));
}
private static Object[] toVarArg(final List © 2015 - 2025 Weber Informatics LLC | Privacy Policy