package rocks.inspectit.server.storage; import java.io.IOException; import java.util.Collection; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import rocks.inspectit.server.dao.impl.PlatformIdentDaoImpl; import rocks.inspectit.server.service.BusinessContextManagementService; import rocks.inspectit.shared.all.cmr.model.PlatformIdent; import rocks.inspectit.shared.all.communication.DefaultData; import rocks.inspectit.shared.all.communication.data.cmr.BusinessTransactionData; import rocks.inspectit.shared.all.spring.logger.Log; import rocks.inspectit.shared.all.util.TimeFrame; import rocks.inspectit.shared.cs.ci.BusinessContextDefinition; import rocks.inspectit.shared.cs.cmr.service.IBusinessContextManagementService; import rocks.inspectit.shared.cs.storage.StorageFileType; import rocks.inspectit.shared.cs.storage.StorageWriter; import rocks.inspectit.shared.cs.storage.label.ObjectStorageLabel; import rocks.inspectit.shared.cs.storage.label.type.impl.DataTimeFrameLabelType; /** * {@link StorageWriter} implementation for the CMR. * * @author Ivan Senic * */ @Component("cmrStorageWriter") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) @Lazy public class CmrStorageWriter extends StorageWriter { /** * The log of this class. */ @Log Logger log; /** * Set of involved Agents, used after recording to store proper Agent information. */ private Set<Long> involvedAgentsSet = new HashSet<>(); /** * {@link AtomicLong} holding the time-stamp value of the oldest data written in the storage. */ private final AtomicLong oldestDataTimestamp = new AtomicLong(Long.MAX_VALUE); /** * {@link AtomicLong} holding the time-stamp value of the newest data written in the storage. */ private final AtomicLong newestDataTimestamp = new AtomicLong(0); /** * Platform ident dao. */ @Autowired private PlatformIdentDaoImpl platformIdentDao; /** * {@link BusinessContextManagementService}. */ @Autowired private IBusinessContextManagementService businessContextService; /** * {@inheritDoc} */ @Override public Future<Void> write(DefaultData defaultData) { Future<Void> future = super.write(defaultData); postWriteOperations(defaultData); return future; } /** * {@inheritDoc} */ @Override public Future<Void> write(DefaultData defaultData, Map<?, ?> kryoPreferences) { Future<Void> future = super.write(defaultData, kryoPreferences); postWriteOperations(defaultData); return future; } /** * {@inheritDoc} * * @throws IOException */ protected void writeAgentData() throws IOException { List<PlatformIdent> involvedPlatformIdents = platformIdentDao.findAllInitialized(involvedAgentsSet); for (PlatformIdent agent : involvedPlatformIdents) { super.writeNonDefaultDataObject(agent, agent.getId() + StorageFileType.AGENT_FILE.getExtension()); } } /** * Writes current {@link BusinessContextDefinition} data of the corresponding CMR to storage. * * @throws IOException * thrown if storing business context fails */ protected void writeBusinessContextData() throws IOException { Collection<BusinessTransactionData> businessTransactions = businessContextService.getBusinessTransactions(); super.writeNonDefaultDataObject(businessTransactions, StorageFileType.BUSINESS_CONTEXT_FILE.getDefaultFileName() + StorageFileType.BUSINESS_CONTEXT_FILE.getExtension()); } /** * {@inheritDoc} */ @Override public synchronized void finalizeWrite() { try { writeAgentData(); writeBusinessContextData(); } catch (IOException e) { log.error("Exception trying to write agent data to disk.", e); } super.finalizeWrite(); if ((newestDataTimestamp.get() > 0) && (oldestDataTimestamp.get() < Long.MAX_VALUE)) { TimeFrame timeFrame = new TimeFrame(new Date(oldestDataTimestamp.get()), new Date(newestDataTimestamp.get())); ObjectStorageLabel<TimeFrame> timeframeLabel = new ObjectStorageLabel<>(timeFrame, new DataTimeFrameLabelType()); getStorageData().addLabel(timeframeLabel, true); } } /** * Executes post write operations: * * <ul> * <li>Remembers the platform id of the written data * <li>Updates the {@link #newestDataTimestamp} and the {@link #oldestDataTimestamp} if needed. * </ul> * * @param defaultData * {@link DefaultData} that has been written. */ private void postWriteOperations(DefaultData defaultData) { involvedAgentsSet.add(defaultData.getPlatformIdent()); while (true) { long oldestData = oldestDataTimestamp.get(); if (oldestData > defaultData.getTimeStamp().getTime()) { if (oldestDataTimestamp.compareAndSet(oldestData, defaultData.getTimeStamp().getTime())) { break; } } else { break; } } while (true) { long newestData = newestDataTimestamp.get(); if (newestData < defaultData.getTimeStamp().getTime()) { if (newestDataTimestamp.compareAndSet(newestData, defaultData.getTimeStamp().getTime())) { break; } } else { break; } } } /** * @param platformIdentDao * the platformIdentDao to set */ public void setPlatformIdentDao(PlatformIdentDaoImpl platformIdentDao) { this.platformIdentDao = platformIdentDao; } }