/* * $Id$ * * Copyright 2011 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.services.pixeldata; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import ome.model.meta.EventLog; import ome.services.eventlogs.EventLogLoader; /** * {@link EventLogLoader} implementation which keeps tracks of the last * {@link EventLog} instance, and always provides the next unindexed instance. * Reseting that saved value would restart indexing. * * @author Josh Moore, josh at glencoesoftware.com * @since Beta4.3 */ public class PersistentEventLogLoader extends ome.services.eventlogs.PersistentEventLogLoader { protected final String repo; /** * The lowest entity id from a single dataPerUser set. */ protected long lowestEntityId = -1; protected final int numThreads; protected List<long[]> dataPerUser = null; public PersistentEventLogLoader(String repo, int numThreads) { this.repo = repo; this.numThreads = numThreads; } @Override public void initialize() { // no-op } /** * Uses data from the {@link #dataPerUser} "queue" to allow new requests to * be processed even if one user adds a large number of PIXELDATA events. * Only the lowest event log id will be saved as the {@link #getCurrentId()} * meaning that some event logs will be processed multiple times. The call * to create the pyramid must properly ignore existing pyramids. */ @Override protected EventLog query() { if (available()) { return pop(); } else { final long current_id = getCurrentId(); if (log.isDebugEnabled()) { log.debug(String.format( "Locating next PIXELSDATA EventLog repo:%s > id:%d", repo, current_id)); } // Taking a multiple of the numThreads that takes a few as possible // from the second row. dataPerUser = new ArrayList<long[]>(); List<long[]> tmp = sql.nextPixelsDataLogForRepo(repo, current_id, numThreads); while (tmp.size() > 0) { long[] data = tmp.remove(0); if (dataPerUser.size() < numThreads) { dataPerUser.add(data); // If we haven't covered the threads, take it log.debug("Data: " + Arrays.toString(data)); } else if (data[3] == 1) { dataPerUser.add(data); // If this is the first per user, take it. log.debug("Data: " + Arrays.toString(data)); } else { log.debug("Skip: " + Arrays.toString(data)); } } if (available()) { return pop(); } } return null; } protected boolean available() { return dataPerUser != null && dataPerUser.size() > 0; } protected EventLog pop() { if (!available()) { throw new IllegalStateException(); } long[] data = dataPerUser.remove(0); final long experimenter = data[0]; final long eventLog = data[1]; final long pixels = data[2]; final long row = data[3]; if (log.isDebugEnabled()) { log.debug(String.format("Handling pixels id:%d for user id:%d", pixels, experimenter)); } // Store the lowest of the entity ids. if (lowestEntityId < 0) { lowestEntityId = eventLog; } else { if (lowestEntityId > eventLog) { lowestEntityId = eventLog; } } // If we are finished, then save this as current id if (!available()) { dataPerUser = null; try { setCurrentId(lowestEntityId); } finally { lowestEntityId = -1; } } return queryService.get(EventLog.class, eventLog); } }