Skip to content

Commit

Permalink
Client-side integration of server-side restore operation
Browse files Browse the repository at this point in the history
  • Loading branch information
georgweiss committed May 16, 2024
1 parent 3771215 commit 9e59351
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 86 deletions.
15 changes: 15 additions & 0 deletions services/save-and-restore/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@
<artifactId>core-pv</artifactId>
<version>4.7.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-pv-pva</artifactId>
<version>4.7.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-pv-ca</artifactId>
<version>4.7.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.phoebus</groupId>
<artifactId>core-vtype</artifactId>
<version>4.7.4-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,61 +1,43 @@
package org.phoebus.service.saveandrestore.epics;

import org.phoebus.applications.saveandrestore.model.RestoreResult;
import org.phoebus.applications.saveandrestore.model.SnapshotItem;
import org.phoebus.core.vtypes.VTypeHelper;
import org.phoebus.framework.preferences.PropertyPreferenceLoader;
import org.phoebus.pv.PV;
import org.phoebus.pv.PVPool;

import java.io.File;
import java.io.FileInputStream;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import org.epics.pva.client.PVAClient;
import org.epics.vtype.VBoolean;
import org.epics.vtype.VBooleanArray;
import org.epics.vtype.VByteArray;
import org.epics.vtype.VDoubleArray;
import org.epics.vtype.VEnum;
import org.epics.vtype.VEnumArray;
import org.epics.vtype.VFloatArray;
import org.epics.vtype.VIntArray;
import org.epics.vtype.VLongArray;
import org.epics.vtype.VNumber;
import org.epics.vtype.VNumberArray;
import org.epics.vtype.VShortArray;
import org.epics.vtype.VString;
import org.epics.vtype.VStringArray;
import org.epics.vtype.VType;
import org.epics.vtype.VUByteArray;
import org.epics.vtype.VUIntArray;
import org.epics.vtype.VULongArray;
import org.epics.vtype.VUShortArray;

import org.phoebus.applications.saveandrestore.model.RestoreResult;
import org.phoebus.framework.preferences.PropertyPreferenceLoader;
import org.phoebus.applications.saveandrestore.model.SnapshotItem;
import org.phoebus.core.vtypes.VTypeHelper;
import org.phoebus.pv.PV;
import org.phoebus.pv.PVPool;

public class SnapshotRestorer {

PVAClient pva;
private final Logger LOG = Logger.getLogger(SnapshotRestorer.class.getName());

public SnapshotRestorer() throws Exception {
pva = new PVAClient();
public SnapshotRestorer() {
final File site_settings = new File("settings.ini");
if (site_settings.canRead()) {
LOG.config("Loading settings from " + site_settings);
PropertyPreferenceLoader.load(new FileInputStream(site_settings));
try {
PropertyPreferenceLoader.load(new FileInputStream(site_settings));
} catch (Exception e) {
LOG.log(Level.WARNING, "Unable to read settings.ini, falling back to default values.");
}
}
}

/**
* Restore PV values from a list of snapshot items
*
* <p>
* Writes concurrently the pv value to the non null set PVs in
* Writes concurrently the pv value to the non-null set PVs in
* the snapshot items.
* Uses synchonized to ensure only one frontend can write at a time.
* Uses synchronized to ensure only one frontend can write at a time.
* Returns a list of the snapshot items you have set, with an error message if
* an error occurred.
*
Expand All @@ -64,11 +46,11 @@ public SnapshotRestorer() throws Exception {
public synchronized List<RestoreResult> restorePVValues(List<SnapshotItem> snapshotItems) {

var futures = snapshotItems.stream().filter(
(snapshot_item) -> snapshot_item.getConfigPv().getPvName() != null)
(snapshot_item) -> snapshot_item.getConfigPv().getPvName() != null)
.map((snapshotItem) -> {
var pvName = snapshotItem.getConfigPv().getPvName();
var pvValue = snapshotItem.getValue();
Object rawValue = vTypeToObject(pvValue);
Object rawValue = VTypeHelper.toObject(pvValue);
PV pv;
CompletableFuture<?> future;
try {
Expand Down Expand Up @@ -96,58 +78,14 @@ public synchronized List<RestoreResult> restorePVValues(List<SnapshotItem> snaps
return restoreResult;
});
})
.collect(Collectors.toList());
.toList();

CompletableFuture<Void> all_done = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

// Wait on the futures concurrently
all_done.join();

// Joins should not block as all the futures should be completed.
return futures.stream().map(
(future) -> future.join()).collect(Collectors.toList());
}

/**
* Convert a vType to its Object representation
*
* @param type {@link VType}
*/
private Object vTypeToObject(VType type) {
if (type == null) {
return null;
}
if (type instanceof VNumberArray) {
if (type instanceof VIntArray || type instanceof VUIntArray) {
return VTypeHelper.toIntegers(type);
} else if (type instanceof VDoubleArray) {
return VTypeHelper.toDoubles(type);
} else if (type instanceof VFloatArray) {
return VTypeHelper.toFloats(type);
} else if (type instanceof VLongArray || type instanceof VULongArray) {
return VTypeHelper.toLongs(type);
} else if (type instanceof VShortArray || type instanceof VUShortArray) {
return VTypeHelper.toShorts(type);
} else if (type instanceof VByteArray || type instanceof VUByteArray) {
return VTypeHelper.toBytes(type);
}
} else if (type instanceof VEnumArray) {
List<String> data = ((VEnumArray) type).getData();
return data.toArray(new String[data.size()]);
} else if (type instanceof VStringArray) {
List<String> data = ((VStringArray) type).getData();
return data.toArray(new String[data.size()]);
} else if (type instanceof VBooleanArray) {
return VTypeHelper.toBooleans(type);
} else if (type instanceof VNumber) {
return ((VNumber) type).getValue();
} else if (type instanceof VEnum) {
return ((VEnum) type).getIndex();
} else if (type instanceof VString) {
return ((VString) type).getValue();
} else if (type instanceof VBoolean) {
return ((VBoolean) type).getValue();
}
return null;
return futures.stream().map(CompletableFuture::join).collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
*/
package org.phoebus.service.saveandrestore.web.config;

import org.phoebus.service.saveandrestore.epics.SnapshotRestorer;
import org.phoebus.service.saveandrestore.persistence.dao.NodeDAO;
import org.phoebus.service.saveandrestore.persistence.dao.impl.elasticsearch.ElasticsearchDAO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
* {@link Configuration} class setting up beans for {@link org.springframework.stereotype.Controller} classes.
Expand All @@ -47,4 +49,11 @@ public NodeDAO nodeDAO() {
public AcceptHeaderResolver acceptHeaderResolver() {
return new AcceptHeaderResolver();
}

@SuppressWarnings("unused")
@Bean
@Scope("singleton")
public SnapshotRestorer snapshotRestorer(){
return new SnapshotRestorer();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,18 @@ public class SnapshotRestoreController extends BaseController {
@Autowired
private NodeDAO nodeDAO;

@Autowired
private SnapshotRestorer snapshotRestorer;

@PostMapping(value = "/restore/items", produces = JSON)
public List<RestoreResult> restoreFromSnapshotItems(
@RequestBody List<SnapshotItem> snapshotItems) throws Exception {
var snapshotRestorer = new SnapshotRestorer();
@RequestBody List<SnapshotItem> snapshotItems) {
return snapshotRestorer.restorePVValues(snapshotItems);
}

@PostMapping(value = "/restore/node", produces = JSON)
public List<RestoreResult> restoreFromSnapshotNode(
@RequestParam(value = "nodeId") String nodeId) throws Exception {
var snapshotRestorer = new SnapshotRestorer();
@RequestParam(value = "nodeId") String nodeId){
var snapshot = nodeDAO.getSnapshotData(nodeId);
return snapshotRestorer.restorePVValues(snapshot.getSnapshotItems());
}
Expand Down

0 comments on commit 9e59351

Please sign in to comment.