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

com.googlecode.objectify.insight.Collector Maven / Gradle / Ivy

package com.googlecode.objectify.insight;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.java.Log;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;

/**
 * Aggregates statistics and flushes them to a pull queue as necessary. Thread-safe. You should
 * create just one of these per application and pass it into all InsightAsyncDatastoreService instances.
 */
@Log
@Singleton
public class Collector {

	/** Where we flush statistics when we cross thresholds */
	@Getter
	private final Flusher flusher;

	/** Date at which the first bucket as added; null if empty */
	private Date oldest;

	/**
	 * Maximum number of unique buckets before we flush. Since all buckets get JSONified into a single
	 * queue task, the hard limit for this is determined by the max size of a task (1 MB).
	 */
	@Getter @Setter
	private int sizeThreshold = 1000;

	/** Maximum age of a bucket before we flush */
	@Getter @Setter
	private long ageThresholdMillis = 30 * 1000;

	/**
	 * Buckets we aggregate into; this is recreated every flush and instantiated lazily.
	 * Use the buckets() method internally.
	 */
	private Map lazyBuckets;

	/**
	 * Use the standard Flusher & Clock
	 */
	public Collector() {
		this(new Flusher());
	}

	/**
	 */
	@Inject
	public Collector(Flusher flusher) {
		this.flusher = flusher;
	}

	/** Use this instead of referencing the lazy var explicitly */
	private Map buckets() {
		if (lazyBuckets == null)
			lazyBuckets = new LinkedHashMap<>(sizeThreshold + sizeThreshold / 3);	// what guava uses for best guess

		return lazyBuckets;
	}

	/**
	 * Collect some statistics. The bucket will be merged with an equivalent bucket.
	 *
	 * @param bucket
	 */
	public synchronized void collect(Bucket bucket) {
		if (log.isLoggable(Level.FINEST))
			log.finest("Collecting bucket " + bucket);

		if (oldest == null)
			oldest = new Date();

		Bucket existing = buckets().get(bucket.getKey());
		if (existing == null) {
			existing = new Bucket(bucket.getKey());
			buckets().put(existing.getKey(), existing);
		}

		existing.merge(bucket);

		// Check time before size because flush() wipes out time
		if (oldest.getTime() + ageThresholdMillis <= System.currentTimeMillis())
			flush();

		if (buckets().size() >= sizeThreshold)
			flush();
	}

	/** Flush the accumulated statistics and reset the collection. */
	private void flush() {
		flusher.flush(buckets().values());
		lazyBuckets = null;
		oldest = null;
	}

	/**
	 * Only present for testing and debugging
	 */
	public synchronized Bucket getBucket(BucketKey bucketKey) {
		return buckets().get(bucketKey);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy