Skip to content

Commit d9cd17f

Browse files
committed
Save&restore search for snapshots contained in composite snapshots. Server parts
1 parent d6d8ea4 commit d9cd17f

File tree

5 files changed

+215
-4
lines changed

5 files changed

+215
-4
lines changed

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/persistence/dao/impl/elasticsearch/CompositeSnapshotDataRepository.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import co.elastic.clients.elasticsearch._types.Refresh;
2323
import co.elastic.clients.elasticsearch._types.Result;
2424
import co.elastic.clients.elasticsearch._types.query_dsl.MatchAllQuery;
25+
import co.elastic.clients.elasticsearch._types.query_dsl.MatchPhraseQuery;
2526
import co.elastic.clients.elasticsearch.core.CountRequest;
2627
import co.elastic.clients.elasticsearch.core.CountResponse;
2728
import co.elastic.clients.elasticsearch.core.DeleteByQueryRequest;
@@ -40,12 +41,15 @@
4041
import org.elasticsearch.action.search.SearchRequestBuilder;
4142
import org.phoebus.applications.saveandrestore.model.CompositeSnapshot;
4243
import org.phoebus.applications.saveandrestore.model.CompositeSnapshotData;
44+
import org.phoebus.service.saveandrestore.model.ESTreeNode;
45+
import org.phoebus.service.saveandrestore.search.SearchUtil;
4346
import org.springframework.beans.factory.annotation.Autowired;
4447
import org.springframework.beans.factory.annotation.Qualifier;
4548
import org.springframework.beans.factory.annotation.Value;
4649
import org.springframework.data.repository.CrudRepository;
4750
import org.springframework.http.HttpStatus;
4851
import org.springframework.stereotype.Repository;
52+
import org.springframework.util.MultiValueMap;
4953
import org.springframework.web.server.ResponseStatusException;
5054

5155
import java.io.IOException;
@@ -62,13 +66,17 @@
6266
@Repository
6367
public class CompositeSnapshotDataRepository implements CrudRepository<CompositeSnapshotData, String> {
6468

69+
@SuppressWarnings("unused")
6570
@Value("${elasticsearch.composite_snapshot_node.index:saveandrestore_composite_snapshot}")
6671
private String ES_COMPOSITE_SNAPSHOT_INDEX;
6772

6873
@Autowired
6974
@Qualifier("client")
7075
ElasticsearchClient client;
7176

77+
@Autowired
78+
private SearchUtil searchUtil;
79+
7280
private final Logger logger = Logger.getLogger(CompositeSnapshotDataRepository.class.getName());
7381

7482
@Override
@@ -234,4 +242,16 @@ public void deleteAll() {
234242
throw new RuntimeException(e);
235243
}
236244
}
245+
246+
public List<CompositeSnapshotData> containedIn(MultiValueMap<String, String> searchParameters){
247+
248+
SearchRequest searchRequest = searchUtil.buildSearchRequest(searchParameters);
249+
try {
250+
SearchResponse<CompositeSnapshotData> response = client.search(searchRequest, CompositeSnapshotData.class);
251+
return response.hits().hits().stream().map(Hit::source).collect(Collectors.toList());
252+
} catch (IOException e) {
253+
logger.log(Level.SEVERE, "Failed to search for referenced snapshot nodes", e);
254+
throw new RuntimeException(e);
255+
}
256+
}
237257
}

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/persistence/dao/impl/elasticsearch/ConfigurationDataRepository.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import co.elastic.clients.elasticsearch.core.search.Hit;
2727
import co.elastic.clients.transport.endpoints.BooleanResponse;
2828
import org.phoebus.applications.saveandrestore.model.ConfigurationData;
29+
import org.phoebus.applications.saveandrestore.model.Node;
2930
import org.phoebus.service.saveandrestore.search.SearchUtil;
3031
import org.springframework.beans.factory.annotation.Autowired;
3132
import org.springframework.beans.factory.annotation.Qualifier;
@@ -212,6 +213,5 @@ public List<ConfigurationData> searchOnPvName(MultiValueMap<String, String> sear
212213
} catch (IOException e) {
213214
throw new RuntimeException(e);
214215
}
215-
216216
}
217217
}

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/persistence/dao/impl/elasticsearch/ElasticsearchDAO.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,4 +1289,16 @@ public int compare(String s1, String s2) {
12891289
return index1 - index2;
12901290
}
12911291
}
1292+
1293+
public List<Node> containedInCompositeSnapshot(MultiValueMap<String, String> searchParameters){
1294+
List<CompositeSnapshotData> compositeSnapshotDataList = compositeSnapshotDataRepository.containedIn(searchParameters);
1295+
List<String> compositeSnapshotIds = compositeSnapshotDataList.stream().map(CompositeSnapshotData::getUniqueId).toList();
1296+
1297+
Iterable<ESTreeNode> esTreeNodes = elasticsearchTreeRepository.findAllById(compositeSnapshotIds);
1298+
1299+
List<Node> list = new ArrayList<>();
1300+
esTreeNodes.iterator().forEachRemaining(es -> list.add(es.getNode()));
1301+
1302+
return list;
1303+
}
12921304
}

services/save-and-restore/src/main/java/org/phoebus/service/saveandrestore/search/SearchUtil.java

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ public class SearchUtil {
4444
@Value("${elasticsearch.configuration_node.index:saveandrestore_configuration}")
4545
private String ES_CONFIGURATION_INDEX;
4646
@SuppressWarnings("unused")
47+
@Value("${elasticsearch.composite_snapshot_node.index:saveandrestore_composite_snapshot}")
48+
private String ES_COMPOSITE_SNAPSHOT_INDEX;
49+
@SuppressWarnings("unused")
4750
@Value("${elasticsearch.result.size.search.default:100}")
4851
private int defaultSearchSize;
4952
@SuppressWarnings("unused")
@@ -75,7 +78,8 @@ public SearchRequest buildSearchRequest(MultiValueMap<String, String> searchPara
7578
LOG.info(" searchParameters: " + searchParameters);
7679

7780
for (Entry<String, List<String>> parameter : searchParameters.entrySet()) {
78-
switch (parameter.getKey().strip().toLowerCase()) {
81+
String s = parameter.getKey().strip().toLowerCase();
82+
switch (s) {
7983
case "uniqueid":
8084
for (String value : parameter.getValue()) {
8185
for (String pattern : value.split("[|,;]")) {
@@ -211,6 +215,8 @@ public SearchRequest buildSearchRequest(MultiValueMap<String, String> searchPara
211215
from = Integer.parseInt(maxFrom.get());
212216
}
213217
break;
218+
case "containedin":
219+
return buildSearchRequestForContainedIn(searchParameters);
214220
default:
215221
// Unsupported search parameters ignored
216222
break;
@@ -385,4 +391,46 @@ public List<String> getSearchTerms(String searchQueryTerms) {
385391
terms.addAll(remaining.stream().filter(t -> t.length() > 0).collect(Collectors.toList()));
386392
return terms;
387393
}
394+
395+
/**
396+
* Constructs a {@link SearchRequest} search for composite snapshots containing a node id.
397+
* @param searchParameters Map of search parameters where key &quot;containedin&quot; must be present and
398+
* contain at least one value. Note however that only first value is considered.
399+
* If no value is specified, an {@link IllegalArgumentException} is thrown.
400+
* @return A suitable {@link SearchRequest}
401+
*/
402+
private SearchRequest buildSearchRequestForContainedIn(MultiValueMap<String, String> searchParameters){
403+
List<String> value = searchParameters.get("containedin");
404+
if(value.isEmpty()){
405+
throw new IllegalArgumentException("At least one value must be specified for 'containedin'");
406+
}
407+
int from = 0;
408+
List<String> parameter = searchParameters.get("from");
409+
if(parameter != null){
410+
Optional<String> maxFrom = parameter.stream().max(Comparator.comparing(Integer::valueOf));
411+
if (maxFrom.isPresent()) {
412+
from = Integer.parseInt(maxFrom.get());
413+
}
414+
}
415+
int size = maxSearchSize;
416+
parameter = searchParameters.get("size");
417+
if(parameter != null){
418+
Optional<String> maxFrom = parameter.stream().max(Comparator.comparing(Integer::valueOf));
419+
if (maxFrom.isPresent()) {
420+
size = Integer.parseInt(maxFrom.get());
421+
}
422+
}
423+
424+
// Only consider first node id value if multiple are specified
425+
String nodeId = value.get(0);
426+
int _from = from;
427+
int _size = size;
428+
MatchPhraseQuery matchPhraseQuery = MatchPhraseQuery.of(m ->
429+
m.field("referencedSnapshotNodes").query(nodeId));
430+
return SearchRequest.of(s -> s.index(ES_COMPOSITE_SNAPSHOT_INDEX)
431+
.query(matchPhraseQuery._toQuery())
432+
.timeout("60s")
433+
.from(_from)
434+
.size(_size));
435+
}
388436
}

services/save-and-restore/src/test/java/org/phoebus/service/saveandrestore/persistence/dao/impl/DAOTestIT.java

Lines changed: 133 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ public class DAOTestIT {
105105
@Value("${elasticsearch.filter.index:test_saveandrestore_filter}")
106106
private String ES_FILTER_INDEX;
107107

108+
@Value("${elasticsearch.composite_snapshot_node.index:test_saveandrestore_composite_snapshot}")
109+
private String ES_COMPOSITE_SNAPSHOT_INDEX;
110+
108111
private static Alarm alarm;
109112
private static Time time;
110113
private static Display display;
@@ -115,7 +118,6 @@ public void init() {
115118
alarm = Alarm.of(AlarmSeverity.NONE, AlarmStatus.NONE, "name");
116119
display = Display.none();
117120
clearAllData();
118-
System.out.println();
119121
}
120122

121123
@AfterEach
@@ -1826,7 +1828,7 @@ public void testGetAllNodes() {
18261828
*/
18271829
private void clearAllData() {
18281830
List<Node> childNodes = nodeDAO.getChildNodes(Node.ROOT_FOLDER_UNIQUE_ID);
1829-
childNodes.forEach(node -> nodeDAO.deleteNode(node.getUniqueId()));
1831+
childNodes.forEach(node -> nodeDAO.deleteNodes(List.of(node.getUniqueId())));
18301832
nodeDAO.deleteAllFilters();
18311833
}
18321834

@@ -1854,6 +1856,17 @@ public void dropIndices() {
18541856
} catch (IOException e) {
18551857
e.printStackTrace();
18561858
}
1859+
1860+
try {
1861+
BooleanResponse exists = client.indices().exists(ExistsRequest.of(e -> e.index(ES_COMPOSITE_SNAPSHOT_INDEX)));
1862+
if (exists.value()) {
1863+
client.indices().delete(
1864+
DeleteIndexRequest.of(
1865+
c -> c.index(ES_COMPOSITE_SNAPSHOT_INDEX)));
1866+
}
1867+
} catch (IOException e) {
1868+
e.printStackTrace();
1869+
}
18571870
}
18581871

18591872
@Test
@@ -2253,4 +2266,122 @@ public void testSearchForPvs() {
22532266
// No pvs specified -> find all nodes.
22542267
assertEquals(4, searchResult.getHitCount());
22552268
}
2269+
2270+
@Test
2271+
public void testSnapshotContainedInCompositeSnapshot() throws Exception{
2272+
Node rootNode = nodeDAO.getRootNode();
2273+
Node folderNode =
2274+
Node.builder().name("folder").build();
2275+
folderNode = nodeDAO.createNode(rootNode.getUniqueId(), folderNode);
2276+
2277+
//************ Create snapshot1 ************/
2278+
Node config = Node.builder().nodeType(NodeType.CONFIGURATION).name("My config 1").build();
2279+
Configuration configuration = new Configuration();
2280+
configuration.setConfigurationNode(config);
2281+
ConfigurationData configurationData = new ConfigurationData();
2282+
configurationData.setPvList(Arrays.asList(ConfigPv.builder().pvName("pv1").build(),
2283+
ConfigPv.builder().pvName("pv2").build()));
2284+
configuration.setConfigurationData(configurationData);
2285+
2286+
configuration = nodeDAO.createConfiguration(folderNode.getUniqueId(), configuration);
2287+
2288+
SnapshotItem item1 = SnapshotItem.builder().configPv(configuration.getConfigurationData().getPvList().get(0))
2289+
.value(VDouble.of(7.7, alarm, time, display)).build();
2290+
SnapshotItem item2 = SnapshotItem.builder().configPv(configuration.getConfigurationData().getPvList().get(1))
2291+
.value(VDouble.of(7.7, alarm, time, display)).build();
2292+
2293+
Snapshot snapshot = new Snapshot();
2294+
snapshot.setSnapshotNode(Node.builder().nodeType(NodeType.SNAPSHOT).name("snapshot name")
2295+
.description("comment")
2296+
.userName("user").build());
2297+
SnapshotData snapshotData = new SnapshotData();
2298+
snapshotData.setSnapshotItems(Arrays.asList(item1, item2));
2299+
snapshot.setSnapshotData(snapshotData);
2300+
Node newSnapshot1 = nodeDAO.createSnapshot(configuration.getConfigurationNode().getUniqueId(), snapshot).getSnapshotNode();
2301+
//************ End create snapshot1 ************/
2302+
2303+
//************ Create snapshot2 ************/
2304+
Node config2 = Node.builder().nodeType(NodeType.CONFIGURATION).name("My config 2").build();
2305+
Configuration configuration2 = new Configuration();
2306+
configuration2.setConfigurationNode(config2);
2307+
ConfigurationData configurationData2 = new ConfigurationData();
2308+
configurationData2.setPvList(Arrays.asList(ConfigPv.builder().pvName("pv12").build(),
2309+
ConfigPv.builder().pvName("pv22").build()));
2310+
configuration2.setConfigurationData(configurationData2);
2311+
2312+
configuration2 = nodeDAO.createConfiguration(folderNode.getUniqueId(), configuration2);
2313+
2314+
SnapshotItem item12 = SnapshotItem.builder().configPv(configuration2.getConfigurationData().getPvList().get(0))
2315+
.value(VDouble.of(7.7, alarm, time, display)).build();
2316+
SnapshotItem item22 = SnapshotItem.builder().configPv(configuration2.getConfigurationData().getPvList().get(1))
2317+
.value(VDouble.of(7.7, alarm, time, display)).build();
2318+
2319+
Snapshot snapshot2 = new Snapshot();
2320+
snapshot2.setSnapshotNode(Node.builder().nodeType(NodeType.SNAPSHOT).name("snapshot name 2")
2321+
.description("comment")
2322+
.userName("user").build());
2323+
SnapshotData snapshotData2 = new SnapshotData();
2324+
snapshotData2.setSnapshotItems(Arrays.asList(item12, item22));
2325+
snapshot2.setSnapshotData(snapshotData2);
2326+
Node newSnapshot2 = nodeDAO.createSnapshot(configuration2.getConfigurationNode().getUniqueId(), snapshot2).getSnapshotNode();
2327+
//************ End create snapshot2 ************/
2328+
2329+
//************ Create composite snapshot ************/
2330+
Node compositeSnapshotNode = Node.builder().name("My composite snapshot").nodeType(NodeType.COMPOSITE_SNAPSHOT).build();
2331+
2332+
CompositeSnapshot compositeSnapshot = new CompositeSnapshot();
2333+
compositeSnapshot.setCompositeSnapshotNode(compositeSnapshotNode);
2334+
2335+
CompositeSnapshotData compositeSnapshotData = new CompositeSnapshotData();
2336+
compositeSnapshotData.setUniqueId(compositeSnapshotNode.getUniqueId());
2337+
2338+
compositeSnapshotData.setReferencedSnapshotNodes(Arrays.asList(snapshot.getSnapshotNode().getUniqueId(),
2339+
snapshot2.getSnapshotNode().getUniqueId()));
2340+
compositeSnapshot.setCompositeSnapshotData(compositeSnapshotData);
2341+
2342+
compositeSnapshot = nodeDAO.createCompositeSnapshot(folderNode.getUniqueId(), compositeSnapshot);
2343+
//************ End create composite snapshot ************/
2344+
2345+
MultiValueMap<String, String> searchParameters = new LinkedMultiValueMap<>();
2346+
searchParameters.put("containedin", List.of(newSnapshot1.getUniqueId()));
2347+
searchParameters.put("from", List.of("0"));
2348+
searchParameters.put("size", List.of("100"));
2349+
2350+
List<Node> nodes = nodeDAO.containedInCompositeSnapshot(searchParameters);
2351+
2352+
assertEquals(nodes.size(), 1);
2353+
2354+
//************ Create another composite snapshot ************/
2355+
Node compositeSnapshotNode2 = Node.builder().name("My composite snapshot 2").nodeType(NodeType.COMPOSITE_SNAPSHOT).build();
2356+
2357+
CompositeSnapshot compositeSnapshot2 = new CompositeSnapshot();
2358+
compositeSnapshot2.setCompositeSnapshotNode(compositeSnapshotNode2);
2359+
2360+
CompositeSnapshotData compositeSnapshotData2 = new CompositeSnapshotData();
2361+
compositeSnapshotData2.setUniqueId(compositeSnapshotNode2.getUniqueId());
2362+
2363+
compositeSnapshotData2.setReferencedSnapshotNodes(Arrays.asList(snapshot.getSnapshotNode().getUniqueId(),
2364+
snapshot2.getSnapshotNode().getUniqueId()));
2365+
compositeSnapshot2.setCompositeSnapshotData(compositeSnapshotData2);
2366+
2367+
nodeDAO.createCompositeSnapshot(folderNode.getUniqueId(), compositeSnapshot2);
2368+
//************ End create another composite snapshot ************/
2369+
2370+
nodes = nodeDAO.containedInCompositeSnapshot(searchParameters);
2371+
2372+
assertEquals(nodes.size(), 2);
2373+
2374+
searchParameters.put("containedin", List.of("non-existing"));
2375+
2376+
nodes = nodeDAO.containedInCompositeSnapshot(searchParameters);
2377+
2378+
assertEquals(nodes.size(), 0);
2379+
2380+
searchParameters.put("containedin", Collections.emptyList());
2381+
2382+
assertThrows(IllegalArgumentException.class, () -> nodeDAO.containedInCompositeSnapshot(searchParameters));
2383+
2384+
nodeDAO.deleteNode(compositeSnapshotNode.getUniqueId());
2385+
nodeDAO.deleteNode(compositeSnapshotNode2.getUniqueId());
2386+
}
22562387
}

0 commit comments

Comments
 (0)