/* Copyright 2012 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.arbeitspferde.groningen.experimentdb; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import org.arbeitspferde.groningen.config.PipelineScoped; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Logger; /** * The ExperimentDb contains Groningen data generated and used by each of the major Groningen * components. The primary purpose of the Experiment Database is to hold pipeline data that is * shared between the Groningen pipeline stages. This includes the JVM parameters of mutated * subjects, their GC log data and the updated JVM arguments comprising a new population. Pipeline * stages do not directly share data, but instead read and write the ExperimentDb. */ @PipelineScoped public class ExperimentDb { /* * TODO(team): Add all calls for pause time caching to blocking GC phases * TODO(team): Store JVM arguments from subjects * TODO(team): Implement get methods to feed pipe stages * TODO(team): Store mutated JVM arguments for the next generation * TODO(team): Complete caching PauseTime and ResourceMetric for scoring */ /** Logger for this class */ private static final Logger log = Logger.getLogger(ExperimentDb.class.getCanonicalName()); private static final Joiner spaceSeparator = Joiner.on(" "); private static final Joiner commaSpaceSeparator = Joiner.on(", "); /** A subject id counter */ private long localSubjectId = 0; /** * The current ID of experiments. It is guaranteed to be unique per program invocation and * hosting address but nothing more. */ private long currentExperimentId = 0; /** Experiments of this run */ private Experiment lastExperiment; private Map<Long, SubjectStateBridge> subjects = new HashMap<>(); public void reset(ExperimentDb anotherDb) { localSubjectId = anotherDb.localSubjectId; currentExperimentId = anotherDb.currentExperimentId; lastExperiment = anotherDb.lastExperiment; subjects = new HashMap<>(anotherDb.subjects); } /** Returns a string serializing and displaying list elements for humans. */ public static String buildStringFromList(final List<?> list) { return commaSpaceSeparator.join(list); } public static void write(final String methodName, final Object... values) { final StringBuilder output = new StringBuilder(); output.append("ExperimentDb ").append(methodName).append(" :"); spaceSeparator.appendTo(output, values); log.info(output.toString()); } /** The logger is being made available so tests can add a handler */ public static Logger getLog() { return log; } public synchronized Experiment makeExperiment(final List<Long> subjectIds) { lastExperiment = new Experiment(ExperimentDb.this, nextExperimentId(), subjectIds); return lastExperiment; } public synchronized Experiment getLastExperiment() { return lastExperiment; } /** Generate a new Experiment ID. */ public synchronized long nextExperimentId() { currentExperimentId++; write("nextExperimentId(local)", currentExperimentId); return currentExperimentId; } public synchronized long getExperimentId() { return currentExperimentId; } public SubjectStateBridge makeSubject() { return makeSubject(nextSubjectId()); } public SubjectStateBridge makeSubject(final long subjectId) { SubjectStateBridge bridge = new SubjectStateBridge(ExperimentDb.this, subjectId); subjects.put(subjectId, bridge); return bridge; } public SubjectStateBridge lookupSubject(final long subjectId) { Preconditions.checkArgument(subjectId >= 0, "subjectId should be > 0"); return subjects.get(subjectId); } /** Generate a new Subject ID */ private synchronized long nextSubjectId() { final long id = ++localSubjectId; write("nextSubjectId(local)", id); return id; } }