org.ogema.resourcemanager.impl.transaction.ResourceTransactionImpl Maven / Gradle / Ivy
The newest version!
/**
* Copyright 2011-2018 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
*
* 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.ogema.resourcemanager.impl.transaction;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import org.ogema.core.application.ApplicationManager;
import org.ogema.core.channelmanager.measurements.SampledValue;
import org.ogema.core.model.Resource;
import org.ogema.core.model.array.BooleanArrayResource;
import org.ogema.core.model.array.ByteArrayResource;
import org.ogema.core.model.array.FloatArrayResource;
import org.ogema.core.model.array.IntegerArrayResource;
import org.ogema.core.model.array.StringArrayResource;
import org.ogema.core.model.array.TimeArrayResource;
import org.ogema.core.model.schedule.Schedule;
import org.ogema.core.model.simple.BooleanResource;
import org.ogema.core.model.simple.FloatResource;
import org.ogema.core.model.simple.IntegerResource;
import org.ogema.core.model.simple.StringResource;
import org.ogema.core.model.simple.TimeResource;
import org.ogema.core.resourcemanager.AccessMode;
import org.ogema.core.resourcemanager.AccessPriority;
import org.ogema.core.resourcemanager.ResourceOperationException;
import org.ogema.core.resourcemanager.transaction.ReadConfiguration;
import org.ogema.core.resourcemanager.transaction.ResourceTransaction;
import org.ogema.core.resourcemanager.transaction.TransactionFuture;
import org.ogema.core.resourcemanager.transaction.WriteConfiguration;
import org.ogema.core.timeseries.ReadOnlyTimeSeries;
import org.ogema.resourcemanager.impl.ResourceDBManager;
import org.ogema.resourcemanager.impl.transaction.actions.AccessModeAction;
import org.ogema.resourcemanager.impl.transaction.actions.AccessModeReadAction;
import org.ogema.resourcemanager.impl.transaction.actions.AccessPriorityReadAction;
import org.ogema.resourcemanager.impl.transaction.actions.ActivationAction;
import org.ogema.resourcemanager.impl.transaction.actions.ActiveReadAction;
import org.ogema.resourcemanager.impl.transaction.actions.CreationAction;
import org.ogema.resourcemanager.impl.transaction.actions.DeletionAction;
import org.ogema.resourcemanager.impl.transaction.actions.ExistenceReadAction;
import org.ogema.resourcemanager.impl.transaction.actions.ReferenceAction;
import org.ogema.resourcemanager.impl.transaction.actions.ResourceReadAction;
import org.ogema.resourcemanager.impl.transaction.actions.ResourceWriteAction;
import org.ogema.resourcemanager.impl.transaction.actions.ScheduleAddAction;
import org.ogema.resourcemanager.impl.transaction.actions.ScheduleReadAction;
import org.ogema.resourcemanager.impl.transaction.actions.ScheduleReplaceAction;
public class ResourceTransactionImpl implements ResourceTransaction {
private volatile boolean commited = false;
private final ResourceDBManager dbMan;
private final ApplicationManager appMan;
private final Queue pending = new LinkedList<>();
private boolean requiresStructureWriteLock = false;
private boolean requiresCommitWriteLock = false;
public ResourceTransactionImpl(ResourceDBManager dbMan, ApplicationManager appMan) {
this.dbMan = dbMan;
this.appMan = appMan;
}
@Override
public void commit() throws ResourceOperationException {
checkStatus();
commited = true;
AtomicAction action;
Deque done = new ArrayDeque<>();
final boolean writeLock = requiresCommitWriteLock;
final boolean structureWriteLock = requiresStructureWriteLock;
lock(structureWriteLock, writeLock);
try {
while ((action = pending.poll()) != null) {
appMan.getLogger().trace("Executing action {} for resource {}",action.getType(),action.getSource());
done.add(action); // add this immediately, so we can try to rollback this action even if it fails
try {
action.execute();
} catch (Exception e) {
// will be rethrown after rollback
appMan.getLogger().warn("Transaction failed at action {} for resource {}",action.getType(), action.getSource());
rollback(done,action,e);
return;
}
}
} finally {
unlock(structureWriteLock, writeLock);
}
}
private void rollback(final Deque actions, AtomicAction source, Exception cause) {
/*
* Avoid using caller's permissions in rollback
*/
AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Void run() {
AtomicAction action;
while ((action = actions.pollLast()) != null) {
try {
appMan.getLogger().debug("Executing rollback {} for resource {}",action.getType(),action.getSource());
action.rollback();
} catch (Exception ee) { // may not be so unusual
appMan.getLogger().warn("Transaction rollback failed",ee);
continue;
}
}
return null;
}
});
pending.clear();
throw new DefaultResourceOperationException(source, cause);
}
private void checkStatus() {
if (commited)
throw new IllegalStateException("Transaction has been commited already.");
}
// FIXME check: is it admissible to obtain structure read lock and then commit write lock?
private void lock(boolean structureWrite, boolean valueWrite) {
if (structureWrite)
dbMan.lockStructureWrite();
else
dbMan.lockStructureRead();
if (valueWrite)
dbMan.lockWrite();
else
dbMan.lockRead();
if (structureWrite || valueWrite)
dbMan.startTransaction();
}
private void unlock(boolean structureWrite, boolean valueWrite) {
if (structureWrite || valueWrite)
dbMan.finishTransaction();
if (valueWrite)
dbMan.unlockWrite();
else
dbMan.unlockRead();
if (structureWrite)
dbMan.unlockStructureWrite();
else
dbMan.unlockStructureRead();
}
// TODO check need for locks
private void addAction(AtomicAction action) {
pending.add(action);
if (action.requiresCommitWriteLock())
requiresCommitWriteLock = true;
if (action.requiresStructureWriteLock())
requiresStructureWriteLock = true;
}
@Override
public void setFloat(FloatResource resource, float value) {
setFloat(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setFloat(FloatResource resource, float value, WriteConfiguration configuration) {
checkStatus();
// addAction(new FloatWriteAction(resource, value, configuration));
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getFloat(FloatResource resource) {
return getFloat(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getFloat(FloatResource resource, ReadConfiguration configuration) {
checkStatus();
// FloatReadAction action = new FloatReadAction(resource, configuration);
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setInteger(IntegerResource resource, int value) {
setInteger(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setInteger(IntegerResource resource, int value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getInteger(IntegerResource resource) {
return getInteger(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getInteger(IntegerResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setBoolean(BooleanResource resource, boolean value) {
setBoolean(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setBoolean(BooleanResource resource, boolean value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getBoolean(BooleanResource resource) {
return getBoolean(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getBoolean(BooleanResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setString(StringResource resource, String value) {
setString(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setString(StringResource resource, String value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getString(StringResource resource) {
return getString(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getString(StringResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setTime(TimeResource resource, long value) {
setTime(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setTime(TimeResource resource, long value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getTime(TimeResource resource) {
return getTime(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getTime(TimeResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setByteArray(ByteArrayResource resource, byte[] value) {
setByteArray(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setByteArray(ByteArrayResource resource, byte[] value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getByteArray(ByteArrayResource resource) {
return getByteArray(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getByteArray(ByteArrayResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setIntegerArray(IntegerArrayResource resource, int[] value) {
setIntegerArray(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setIntegerArray(IntegerArrayResource resource, int[] value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getIntegerArray(IntegerArrayResource resource) {
return getIntegerArray(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getIntegerArray(IntegerArrayResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setBooleanArray(BooleanArrayResource resource, boolean[] value) {
setBooleanArray(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setBooleanArray(BooleanArrayResource resource, boolean[] value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getBooleanArray(BooleanArrayResource resource) {
return getBooleanArray(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getBooleanArray(BooleanArrayResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setFloatArray(FloatArrayResource resource, float[] value) {
setFloatArray(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setFloatArray(FloatArrayResource resource, float[] value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getFloatArray(FloatArrayResource resource) {
return getFloatArray(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getFloatArray(FloatArrayResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setStringArray(StringArrayResource resource, String[] value) {
setStringArray(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setStringArray(StringArrayResource resource, String[] value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getStringArray(StringArrayResource resource) {
return getStringArray(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getStringArray(StringArrayResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void setTimeArray(TimeArrayResource resource, long[] value) {
setTimeArray(resource, value, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setTimeArray(TimeArrayResource resource, long[] value, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction(resource, value, configuration));
}
@Override
public TransactionFuture getTimeArray(TimeArrayResource resource) {
return getTimeArray(resource, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getTimeArray(TimeArrayResource resource, ReadConfiguration configuration) {
checkStatus();
ResourceReadAction action = new ResourceReadAction(resource, configuration);
addAction(action);
return new TransactionFutureImpl<>(action);
}
// TODO interpolation mode
@Override
public void setSchedule(Schedule schedule, ReadOnlyTimeSeries function) {
setSchedule(schedule, function, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void setSchedule(Schedule schedule, ReadOnlyTimeSeries function, WriteConfiguration configuration) {
checkStatus();
addAction(new ResourceWriteAction, Schedule>(schedule, function.getValues(Long.MIN_VALUE), configuration));
}
@Override
public void addSchedule(Schedule schedule, ReadOnlyTimeSeries function) {
addSchedule(schedule, function, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void addSchedule(Schedule schedule, ReadOnlyTimeSeries function, WriteConfiguration configuration) {
addScheduleValues(schedule, function.getValues(Long.MIN_VALUE), configuration);
}
@Override
public void addScheduleValues(Schedule schedule, Collection values) {
addScheduleValues(schedule, values, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void addScheduleValues(Schedule schedule, Collection values, WriteConfiguration configuration) {
checkStatus();
addAction(new ScheduleAddAction(schedule, values, configuration));
}
@Override
public void replaceScheduleValues(Schedule schedule, long starttime, long endtime, Collection values) {
replaceScheduleValues(schedule, starttime, endtime, values, WriteConfiguration.CREATE_AND_ACTIVATE);
}
@Override
public void replaceScheduleValues(Schedule schedule, long starttime, long endtime, Collection values, WriteConfiguration configuration) {
checkStatus();
addAction(new ScheduleReplaceAction(schedule, values, configuration, starttime, endtime));
}
@Override
public TransactionFuture getSchedule(Schedule schedule) {
return getSchedule(schedule,ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getSchedule(Schedule resource, ReadConfiguration configuration) {
return getSchedule(resource, Long.MIN_VALUE, Long.MAX_VALUE, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getSchedule(Schedule schedule, long starttime, long endtime) {
return getSchedule(schedule, starttime, endtime, ReadConfiguration.FAIL);
}
@Override
public TransactionFuture getSchedule(Schedule resource, long starttime, long endtime, ReadConfiguration configuration) {
checkStatus();
ScheduleReadAction action = new ScheduleReadAction(resource, configuration, starttime, endtime);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public void activate(Resource resource) {
activate(resource, true, false);
}
@Override
public void activate(Resource resource, boolean create, boolean recursive) {
checkStatus();
ActivationAction action = new ActivationAction(resource, true, recursive, create);
addAction(action);
}
@Override
public void deactivate(Resource resource) {
deactivate(resource, false);
}
@Override
public void deactivate(Resource resource, boolean recursive) {
checkStatus();
addAction(new ActivationAction(resource, false, recursive, false));
}
@Override
public void create(Resource resource) {
checkStatus();
addAction(new CreationAction(resource));
}
@Override
public void delete(Resource resource) {
checkStatus();
addAction(new DeletionAction(resource,appMan.getResourceManagement()));
}
@Override
public void setAsReference(R resource, R target) {
checkStatus();
addAction(new ReferenceAction(resource, target,appMan.getResourceManagement()));
}
@Override
public TransactionFuture requestAccessMode(Resource resource, AccessMode mode, AccessPriority priority,boolean failOnReject) {
checkStatus();
AccessModeAction action =new AccessModeAction(resource, mode, priority, failOnReject);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public TransactionFuture getAccessMode(Resource resource) {
checkStatus();
AccessModeReadAction action =new AccessModeReadAction(resource);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public TransactionFuture getAccessPriority(Resource resource) {
checkStatus();
AccessPriorityReadAction action =new AccessPriorityReadAction(resource);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public TransactionFuture isActive(Resource resource) {
checkStatus();
ActiveReadAction action = new ActiveReadAction(resource);
addAction(action);
return new TransactionFutureImpl<>(action);
}
@Override
public TransactionFuture exists(Resource resource) {
checkStatus();
ExistenceReadAction action = new ExistenceReadAction(resource);
addAction(action);
return new TransactionFutureImpl<>(action);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy