-
Notifications
You must be signed in to change notification settings - Fork 214
/
SearchUpdateMapper.java
115 lines (104 loc) · 4.47 KB
/
SearchUpdateMapper.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
* Copyright (c) 2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.ditto.thingsearch.service.persistence.write.streaming;
import java.util.List;
import org.eclipse.ditto.base.service.DittoExtensionPoint;
import org.eclipse.ditto.internal.utils.akka.AkkaClassLoader;
import org.eclipse.ditto.internal.utils.metrics.instruments.timer.StartedTimer;
import org.eclipse.ditto.thingsearch.service.persistence.write.model.AbstractWriteModel;
import org.eclipse.ditto.thingsearch.service.updater.actors.MongoWriteModel;
import org.slf4j.Logger;
import akka.NotUsed;
import akka.actor.AbstractExtensionId;
import akka.actor.ActorSystem;
import akka.actor.ExtendedActorSystem;
import akka.stream.javadsl.Source;
/**
* Search Update Mapper to be loaded by reflection.
* Can be used as an extension point to use custom map search updates.
* Implementations MUST have a public constructor taking an actorSystem as argument.
*
* @since 2.1.0
*/
public abstract class SearchUpdateMapper implements DittoExtensionPoint {
private static final ExtensionId EXTENSION_ID = new ExtensionId();
protected final ActorSystem actorSystem;
protected SearchUpdateMapper(final ActorSystem actorSystem) {
this.actorSystem = actorSystem;
}
/**
* Gets a write model of the search update and processes it.
*
* @param writeModel the write model.
* @param lastWriteModel the last write model to compute incremental update from.
* @return Ditto write model together with its processed MongoDB write model.
*/
public abstract Source<MongoWriteModel, NotUsed> processWriteModel(AbstractWriteModel writeModel,
final AbstractWriteModel lastWriteModel);
/**
* Load a {@code SearchUpdateListener} dynamically according to the search configuration.
*
* @param actorSystem The actor system in which to load the listener.
* @return The listener.
*/
public static SearchUpdateMapper get(final ActorSystem actorSystem) {
return EXTENSION_ID.get(actorSystem);
}
/**
* Convert a write model to an incremental update model.
*
* @param model the write model.
* @param logger the logger.
* @return a singleton list of write model together with its update document, or an empty list if there is no
* change.
*/
protected static Source<MongoWriteModel, NotUsed>
toIncrementalMongo(final AbstractWriteModel model, final AbstractWriteModel lastWriteModel, final Logger logger) {
try {
final var mongoWriteModelOpt = model.toIncrementalMongo(lastWriteModel);
if (mongoWriteModelOpt.isEmpty()) {
logger.debug("Write model is unchanged, skipping update: <{}>", model);
model.getMetadata().sendWeakAck(null);
return Source.empty();
} else {
ConsistencyLag.startS5MongoBulkWrite(model.getMetadata());
final var result = mongoWriteModelOpt.orElseThrow();
logger.debug("MongoWriteModel={}", result);
return Source.single(result);
}
}
catch (final Exception error) {
logger.error("Failed to compute write model " + model, error);
try {
model.getMetadata().getTimers().forEach(StartedTimer::stop);
} catch (final Exception e) {
// tolerate stopping stopped timers
}
return Source.empty();
}
}
/**
* ID of the actor system extension to validate the {@code SearchUpdateListener}.
*/
private static final class ExtensionId extends AbstractExtensionId<SearchUpdateMapper> {
private static final String CONFIG_PATH = "ditto.search.search-update-mapper.implementation";
@Override
public SearchUpdateMapper createExtension(final ExtendedActorSystem system) {
final String implementation = system.settings().config().getString(CONFIG_PATH);
return AkkaClassLoader.instantiate(system, SearchUpdateMapper.class,
implementation,
List.of(ActorSystem.class),
List.of(system));
}
}
}