/*
* Copyright 2015-2016 OpenCB
*
* 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.opencb.opencga.storage.core.metadata;
import org.opencb.commons.datastore.core.ObjectMap;
import org.opencb.commons.datastore.core.QueryOptions;
import org.opencb.commons.datastore.core.QueryResult;
import org.opencb.opencga.storage.core.exceptions.StorageEngineException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.TimeoutException;
/**
* @author Jacobo Coll <jacobo167@gmail.com>
*/
public abstract class StudyConfigurationManager implements AutoCloseable {
public static final String CACHED = "cached";
public static final String READ_ONLY = "ro";
protected static Logger logger = LoggerFactory.getLogger(StudyConfigurationManager.class);
private final Map<String, StudyConfiguration> stringStudyConfigurationMap = new HashMap<>();
private final Map<Integer, StudyConfiguration> intStudyConfigurationMap = new HashMap<>();
public StudyConfigurationManager(ObjectMap objectMap) {
}
protected abstract QueryResult<StudyConfiguration> internalGetStudyConfiguration(String studyName, Long time, QueryOptions options);
protected abstract QueryResult<StudyConfiguration> internalGetStudyConfiguration(int studyId, Long timeStamp, QueryOptions options);
public long lockStudy(int studyId) throws StorageEngineException {
try {
return lockStudy(studyId, 10000, 20000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new StorageEngineException("Unable to lock the Study " + studyId, e);
} catch (TimeoutException e) {
throw new StorageEngineException("Unable to lock the Study " + studyId, e);
}
}
public long lockStudy(int studyId, long lockDuration, long timeout) throws InterruptedException, TimeoutException {
logger.warn("Ignoring lock");
return 0;
}
public void unLockStudy(int studyId, long lockId) {
logger.warn("Ignoring unLock");
}
public interface UpdateStudyConfiguration<E extends Exception> {
StudyConfiguration update(StudyConfiguration studyConfiguration) throws E;
}
public <E extends Exception> StudyConfiguration lockAndUpdate(String studyName, UpdateStudyConfiguration<E> updater)
throws StorageEngineException, E {
Integer studyId = getStudies(QueryOptions.empty()).get(studyName);
return lockAndUpdate(studyId, updater);
}
public <E extends Exception> StudyConfiguration lockAndUpdate(int studyId, UpdateStudyConfiguration<E> updater)
throws StorageEngineException, E {
long lock = lockStudy(studyId);
try {
StudyConfiguration sc = getStudyConfiguration(studyId, new QueryOptions(CACHED, false)).first();
sc = updater.update(sc);
updateStudyConfiguration(sc, QueryOptions.empty());
return sc;
} finally {
unLockStudy(studyId, lock);
}
}
protected abstract QueryResult internalUpdateStudyConfiguration(StudyConfiguration studyConfiguration, QueryOptions options);
public final QueryResult<StudyConfiguration> getStudyConfiguration(String studyName, QueryOptions options) {
QueryResult<StudyConfiguration> result;
final boolean cached = options != null && options.getBoolean(CACHED, false);
final boolean readOnly = options != null && options.getBoolean(READ_ONLY, false);
if (stringStudyConfigurationMap.containsKey(studyName)) {
if (cached) {
StudyConfiguration studyConfiguration = stringStudyConfigurationMap.get(studyName);
if (!readOnly) {
studyConfiguration = studyConfiguration.newInstance();
}
return new QueryResult<>(studyConfiguration.getStudyName(), 0, 1, 1, "", "", Collections.singletonList(studyConfiguration));
}
result = internalGetStudyConfiguration(studyName, stringStudyConfigurationMap.get(studyName).getTimeStamp(), options);
if (result.getNumTotalResults() == 0) { //No changes. Return old value
StudyConfiguration studyConfiguration = stringStudyConfigurationMap.get(studyName);
if (!readOnly) {
studyConfiguration = studyConfiguration.newInstance();
}
return new QueryResult<>(studyName, 0, 1, 1, "", "", Collections.singletonList(studyConfiguration));
}
} else {
result = internalGetStudyConfiguration(studyName, null, options);
}
StudyConfiguration studyConfiguration = result.first();
if (studyConfiguration != null) {
intStudyConfigurationMap.put(studyConfiguration.getStudyId(), studyConfiguration);
stringStudyConfigurationMap.put(studyConfiguration.getStudyName(), studyConfiguration);
if (studyName != null && !studyName.equals(studyConfiguration.getStudyName())) {
stringStudyConfigurationMap.put(studyName, studyConfiguration);
}
if (!readOnly) {
result.setResult(Collections.singletonList(studyConfiguration.newInstance()));
}
}
return result;
}
public final QueryResult<StudyConfiguration> getStudyConfiguration(int studyId, QueryOptions options) {
QueryResult<StudyConfiguration> result;
final boolean cached = options != null && options.getBoolean(CACHED, false);
final boolean readOnly = options != null && options.getBoolean(READ_ONLY, false);
if (intStudyConfigurationMap.containsKey(studyId)) {
if (cached) {
StudyConfiguration studyConfiguration = intStudyConfigurationMap.get(studyId);
if (!readOnly) {
studyConfiguration = studyConfiguration.newInstance();
}
return new QueryResult<>(studyConfiguration.getStudyName(), 0, 1, 1, "", "", Collections.singletonList(studyConfiguration));
}
result = internalGetStudyConfiguration(studyId, intStudyConfigurationMap.get(studyId).getTimeStamp(), options);
if (result.getNumTotalResults() == 0) { //No changes. Return old value
StudyConfiguration studyConfiguration = intStudyConfigurationMap.get(studyId);
if (!readOnly) {
studyConfiguration = studyConfiguration.newInstance();
}
return new QueryResult<>(studyConfiguration.getStudyName(), 0, 1, 1, "", "", Collections.singletonList(studyConfiguration));
}
} else {
result = internalGetStudyConfiguration(studyId, null, options);
}
StudyConfiguration studyConfiguration = result.first();
if (studyConfiguration != null) {
intStudyConfigurationMap.put(studyConfiguration.getStudyId(), studyConfiguration);
stringStudyConfigurationMap.put(studyConfiguration.getStudyName(), studyConfiguration);
if (!readOnly) {
result.setResult(Collections.singletonList(studyConfiguration.newInstance()));
}
}
return result;
}
public List<String> getStudyNames(QueryOptions options) {
return new ArrayList<>(getStudies(options).keySet());
}
public List<Integer> getStudyIds(QueryOptions options) {
return new ArrayList<>(getStudies(options).values());
}
public abstract Map<String, Integer> getStudies(QueryOptions options);
public final QueryResult updateStudyConfiguration(StudyConfiguration studyConfiguration, QueryOptions options) {
long timeStamp = System.currentTimeMillis();
logger.debug("Timestamp : {} -> {}", studyConfiguration.getTimeStamp(), timeStamp);
studyConfiguration.setTimeStamp(timeStamp);
Map<Integer, String> headers = studyConfiguration.getHeaders();
studyConfiguration.setHeaders(null);
logger.debug("Updating studyConfiguration : {}", studyConfiguration.toJson());
studyConfiguration.setHeaders(headers);
// Store a copy of the StudyConfiguration.
StudyConfiguration copy = studyConfiguration.newInstance();
stringStudyConfigurationMap.put(copy.getStudyName(), copy);
intStudyConfigurationMap.put(copy.getStudyId(), copy);
return internalUpdateStudyConfiguration(copy, options);
}
public static StudyConfigurationManager build(String className, ObjectMap params)
throws ReflectiveOperationException {
try {
Class<?> clazz = Class.forName(className);
if (StudyConfigurationManager.class.isAssignableFrom(clazz)) {
return (StudyConfigurationManager) clazz.getConstructor(ObjectMap.class).newInstance(params);
} else {
throw new ReflectiveOperationException("Clazz " + className + " is not a subclass of StudyConfigurationManager");
}
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException
| InvocationTargetException e) {
logger.error("Unable to create StudyConfigurationManager");
throw e;
}
}
@Override
public void close() throws IOException { }
}