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

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

There is a newer version: 7.0
Show newest version
package com.nimbusds.infinispan.persistence.dynamodb;


import java.util.Date;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;

import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.codahale.metrics.Timer;
import net.jcip.annotations.ThreadSafe;
import org.infinispan.marshall.core.MarshalledEntry;
import org.infinispan.marshall.core.MarshalledEntryFactory;
import org.infinispan.metadata.InternalMetadata;
import org.infinispan.persistence.spi.AdvancedCacheExpirationWriter;
import org.infinispan.persistence.spi.AdvancedCacheWriter;
import org.infinispan.persistence.spi.PersistenceException;

import com.nimbusds.infinispan.persistence.common.InfinispanEntry;
import com.nimbusds.infinispan.persistence.dynamodb.logging.Loggers;


/**
 * Reaper of expired persisted Infinispan entries.
 */
@ThreadSafe
class ExpiredEntryReaper {
	
	
	/**
	 * The Infinispan marshalled entry factory.
	 */
	private final MarshalledEntryFactory marshalledEntryFactory;
	
	
	/**
	 * The DynamoDB table.
	 */
	private final Table table;


	/**
	 * The DynamoDB request factory.
	 */
	private final RequestFactory requestFactory;
	
	
	/**
	 * Limits the number of expired entries to reap, -1 for no limit.
	 */
	private final int maxNumEntriesToReap;
	
	
	/**
	 * The purge timer to use.
	 */
	private final Timer purgeTimer;


	/**
	 * Creates a new reaper for expired persisted Infinispan entries.
	 *
	 * @param marshalledEntryFactory The Infinispan marshalled entry.
	 * @param table                  The DynamoDB table. Must not be
	 *                               {@code null}.
	 *                               factory. Must not be {@code null}.
	 * @param requestFactory         The DynamoDB request factory.
	 * @param maxNumEntriesToReap    Limits the number of expired entries
	 *                               to reap, -1 for no limit.
	 * @param purgeTimer             The purge timer to use.
	 */
	ExpiredEntryReaper(final MarshalledEntryFactory marshalledEntryFactory,
			   final Table table,
			   final RequestFactory requestFactory,
			   final int maxNumEntriesToReap,
			   final Timer purgeTimer) {
		
		assert marshalledEntryFactory != null;
		this.marshalledEntryFactory = marshalledEntryFactory;
		
		assert table != null;
		this.table = table;
		
		assert requestFactory != null;
		this.requestFactory = requestFactory;
		
		this.maxNumEntriesToReap = maxNumEntriesToReap;
		
		assert purgeTimer != null;
		this.purgeTimer = purgeTimer;
	}


	/**
	 * Purges the expired persisted entries according to their metadata
	 * timestamps (if set / persisted).
	 *
	 * @param purgeListener The purge listener. Must not be {@code null}.
	 *
	 * @return The number of purged entries.
	 */
	int purge(final AdvancedCacheWriter.PurgeListener purgeListener) {
		
		Timer.Context timerCtx = purgeTimer.time();
		
		try {
			final long now = new Date().getTime();
			
			final AtomicInteger deleteCounter = new AtomicInteger(0);
			
			Iterator it = requestFactory.getAllItems(table).iterator();
			
			while ((it.hasNext())) {
				
				if (maxNumEntriesToReap > -1 && deleteCounter.get() >= maxNumEntriesToReap) {
					break;
				}
				
				Item item = it.next();
				
				InfinispanEntry infinispanEntry = requestFactory.getItemTransformer().toInfinispanEntry(item);
				
				InternalMetadata metadata = infinispanEntry.getMetadata();
				
				if (metadata == null) {
					continue; // no metadata found
				}
				
				if (! metadata.isExpired(now)) {
					continue;
				}
				
				// Delete batching will not work here, doesn't support
				// attribute retrieval to confirm deletion
				final boolean deleted = table.deleteItem(requestFactory.resolveDeleteItemSpec(infinispanEntry.getKey())).getItem() != null;
				
				if (deleted) {
					// Notify listener, interested in the Infinispan entry key
					purgeListener.entryPurged(infinispanEntry.getKey());
					deleteCounter.incrementAndGet();
				}
			};
			
			Loggers.DYNAMODB_LOG.debug("[DS0128] DynamoDB store: Purged {} expired {} cache entries", deleteCounter.get(), table.getTableName());
			
			return deleteCounter.get();
			
		} catch (Exception e) {
			Loggers.DYNAMODB_LOG.error("[DS0127] {}: {}", e.getMessage(), e);
			throw new PersistenceException("Purge exception: " + e.getMessage(), e);
		} finally {
			timerCtx.stop();
		}
	}


	/**
	 * 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}.
	 *
	 * @return The number of purged entries.
	 */
	int purgeExtended(final AdvancedCacheExpirationWriter.ExpirationPurgeListener purgeListener) {
		
		Timer.Context timerCtx = purgeTimer.time();
		
		try {
			final long now = new Date().getTime();
			
			final AtomicInteger deleteCounter = new AtomicInteger(0);
			
			Iterator it = requestFactory.getAllItems(table).iterator();
			
			while (it.hasNext()){
				
				if (maxNumEntriesToReap > -1 && deleteCounter.get() >= maxNumEntriesToReap) {
					break;
				}
				
				Item item = it.next();
				
				InfinispanEntry infinispanEntry = requestFactory.getItemTransformer().toInfinispanEntry(item);
				
				InternalMetadata metadata = infinispanEntry.getMetadata();
				
				if (metadata == null) {
					continue; // no metadata found
				}
				
				if (! metadata.isExpired(now)) {
					continue;
				}
				
				// Delete batching will not work here, doesn't support
				// attribute retrieval to confirm deletion
				final boolean deleted = table.deleteItem(requestFactory.resolveDeleteItemSpec(infinispanEntry.getKey())).getItem() != null;
				
				if (deleted) {
					// Notify listener, interested in the Infinispan entry
					MarshalledEntry marshalledEntry =
						marshalledEntryFactory.newMarshalledEntry(
							infinispanEntry.getKey(),
							infinispanEntry.getValue(),
							infinispanEntry.getMetadata()
						);
					purgeListener.marshalledEntryPurged(marshalledEntry);
					deleteCounter.incrementAndGet();
				}
				
			}
			
			Loggers.DYNAMODB_LOG.debug("[DS0128] DynamoDB store: Purged {} expired {} cache entries", deleteCounter.get(), table.getTableName());
			
			return deleteCounter.get();
			
		} catch (Exception e) {
			Loggers.DYNAMODB_LOG.error("[DS0151] {}: {}", e.getMessage(), e);
			throw new PersistenceException("Purge exception: " + e.getMessage(), e);
		} finally {
			timerCtx.stop();
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy