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

com.nimbusds.infinispan.persistence.sql.ExpiredEntryReaper Maven / Gradle / Ivy

package com.nimbusds.infinispan.persistence.sql;


import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Function;

import static org.jooq.impl.DSL.table;

import net.jcip.annotations.ThreadSafe;
import org.infinispan.metadata.InternalMetadata;
import org.infinispan.metadata.impl.PrivateMetadata;
import org.infinispan.persistence.spi.AdvancedCacheExpirationWriter;
import org.infinispan.persistence.spi.AdvancedCacheWriter;
import org.infinispan.persistence.spi.MarshallableEntry;
import org.infinispan.persistence.spi.MarshallableEntryFactory;
import org.jooq.DSLContext;
import org.jooq.Record;

import com.nimbusds.infinispan.persistence.common.InfinispanEntry;


/**
 * Expired entry reaper.
 */
@ThreadSafe
class ExpiredEntryReaper {
	
	
	/**
	 * The Infinispan marshallable entry factory.
	 */
	private final MarshallableEntryFactory mEntryFactory;
	
	
	/**
	 * The DSL context.
	 */
	private final DSLContext dsl;


	/**
	 * The SQL record transformer.
	 */
	private final SQLRecordTransformer recordTransformer;
	
	
	/**
	 * The SQL record wrapper.
	 */
	private final Function recordWrapper;


	/**
	 * Creates a new 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.
	 */
	public ExpiredEntryReaper(final MarshallableEntryFactory mEntryFactory,
				  final DSLContext dsl,
				  final SQLRecordTransformer recordTransformer,
				  final Function recordWrapper) {

		assert mEntryFactory != null;
		this.mEntryFactory = mEntryFactory;
		
		assert dsl != null;
		this.dsl = dsl;
		
		assert recordTransformer != null;
		this.recordTransformer = recordTransformer;
		
		assert recordWrapper != null;
		this.recordWrapper = recordWrapper;
	}


	/**
	 * Purges the expired persisted entries according to their metadata
	 * timestamps (if set / persisted).
	 *
	 * @param purgeListener The purge listener. Must not be {@code null}.
	 */
	public void purge(final AdvancedCacheWriter.PurgeListener purgeListener) {

		final long now = new Date().getTime();

		// The keys for deletion
		List forDeletion = new LinkedList<>();
		
		dsl.select()
			.from(table(recordTransformer.getTableName()))
			.stream()
			.forEach(record -> {
				
				RetrievedSQLRecord retrievedRecord = recordWrapper.apply(record);
				
				InfinispanEntry infinispanEntry = recordTransformer.toInfinispanEntry(retrievedRecord);
				
				InternalMetadata metadata = infinispanEntry.getMetadata();
				
				if (metadata == null) {
					return; // no metadata found
				}
				
				if (metadata.isExpired(now)) {
					
					// Mark record for deletion
					forDeletion.add(infinispanEntry.getKey());
				}
			});

		int counter = 0;
		
		for (K key: forDeletion) {

			// Delete SQL record
			int numDeleted = dsl.deleteFrom(table(recordTransformer.getTableName()))
				.where(recordTransformer.resolveSelectionConditions(key))
				.execute();
			
			if (numDeleted == 1) {
				// Notify listener, interested in the Infinispan entry key
				purgeListener.entryPurged(key);
				counter++;
			}
		}
		
		Loggers.SQL_LOG.debug("[IS0128] SQL store: Purged {} expired {} cache entries", counter, recordTransformer.getTableName());
	}
	
	
	/**
	 * Purges the expired persisted entries according to their metadata
	 * timestamps (if set / persisted), with an extended listener for the
	 * complete purged entry.
	 *
	 * @param purgeListener The purge listener. Must not be {@code null}.
	 */
	public void purgeExtended(final AdvancedCacheExpirationWriter.ExpirationPurgeListener purgeListener) {

		final long now = new Date().getTime();

		// The entries for deletion
		List> forDeletion = new LinkedList<>();
		
		dsl.select()
			.from(table(recordTransformer.getTableName()))
			.stream()
			.forEach(record -> {
				
				RetrievedSQLRecord retrievedRecord = recordWrapper.apply(record);
				
				InfinispanEntry infinispanEntry = recordTransformer.toInfinispanEntry(retrievedRecord);
				
				InternalMetadata metadata = infinispanEntry.getMetadata();
				
				if (metadata == null) {
					return; // no metadata found
				}
				
				if (metadata.isExpired(now)) {
					
					// Mark record for deletion
					forDeletion.add(infinispanEntry);
				}
			});
		
		
		int counter = 0;
		
		for (InfinispanEntry en: forDeletion) {

			// Delete SQL record
			int numDeleted = dsl.deleteFrom(table(recordTransformer.getTableName()))
				.where(recordTransformer.resolveSelectionConditions(en.getKey()))
				.execute();
			
			if (numDeleted == 1) {
				// Notify listener, interested in the Infinispan entry
				MarshallableEntry mEntry =
					mEntryFactory.create(
						en.getKey(),
						en.getValue(),
						en.getMetadata(),
						PrivateMetadata.empty(),
						en.created(),
						en.lastUsed()
					);
				purgeListener.marshalledEntryPurged(mEntry);
				counter++;
			}
		}
		
		Loggers.SQL_LOG.debug("[IS0128] SQL store: Purged {} expired {} cache entries", counter, recordTransformer.getTableName());
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy