Skip to content

Commit 775f2b3

Browse files
authored
Persistence timeseries fix updating Item state (#5403)
* correct alias when storing timeseries * call handleExternalPersistenceDataChange from persistence extensions when persisting or removing * set item state if current state update time before restored entry in timeseries Signed-off-by: Mark Herwege <mark.herwege@telenet.be>
1 parent abdda02 commit 775f2b3

6 files changed

Lines changed: 450 additions & 118 deletions

File tree

bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/PersistenceManager.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,16 @@
2424
*/
2525
@NonNullByDefault
2626
public interface PersistenceManager {
27+
28+
/**
29+
* External code that updates persisted data, that may have an impact on the persistence logic (restoring item
30+
* states, forecast logic), should call this method to inform the {@link PersistenceManager} about a potential
31+
* impact. The {@link PersistenceManager} will query the service again to get the necessary information. This all
32+
* happens in the calling thread and may therefore take some time. If this is undesired, this call should be
33+
* performed asynchronously.
34+
*
35+
* @param persistenceService the persistence service
36+
* @param item the item for which persisted data has been updated
37+
*/
2738
void handleExternalPersistenceDataChange(PersistenceService persistenceService, Item item);
2839
}

bundles/org.openhab.core.persistence/src/main/java/org/openhab/core/persistence/extensions/PersistenceExtensions.java

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.openhab.core.persistence.FilterCriteria.Ordering;
4141
import org.openhab.core.persistence.HistoricItem;
4242
import org.openhab.core.persistence.ModifiablePersistenceService;
43+
import org.openhab.core.persistence.PersistenceManager;
4344
import org.openhab.core.persistence.PersistenceService;
4445
import org.openhab.core.persistence.PersistenceServiceRegistry;
4546
import org.openhab.core.persistence.QueryablePersistenceService;
@@ -73,11 +74,13 @@
7374
* @author Mark Herwege - use item lastChange and lastUpdate methods if not in peristence
7475
* @author Mark Herwege - add Riemann sum methods
7576
* @author Jörg Sautter - use Instant instead of ZonedDateTime in Riemann sum methods
77+
* @author Mark Herwege - handle timeseries update
7678
*/
7779
@Component(immediate = true)
7880
@NonNullByDefault
7981
public class PersistenceExtensions {
8082

83+
private static @Nullable PersistenceManager manager;
8184
private static @Nullable PersistenceServiceRegistry registry;
8285
private static @Nullable PersistenceServiceConfigurationRegistry configRegistry;
8386
private static @Nullable TimeZoneProvider timeZoneProvider;
@@ -90,9 +93,10 @@ public static enum RiemannType {
9093
}
9194

9295
@Activate
93-
public PersistenceExtensions(@Reference PersistenceServiceRegistry registry,
96+
public PersistenceExtensions(@Reference PersistenceManager manager, @Reference PersistenceServiceRegistry registry,
9497
@Reference PersistenceServiceConfigurationRegistry configRegistry,
9598
@Reference TimeZoneProvider timeZoneProvider) {
99+
PersistenceExtensions.manager = manager;
96100
PersistenceExtensions.registry = registry;
97101
PersistenceExtensions.configRegistry = configRegistry;
98102
PersistenceExtensions.timeZoneProvider = timeZoneProvider;
@@ -126,6 +130,9 @@ private static void internalPersist(Item item, @Nullable String serviceId) {
126130
PersistenceService service = getService(effectiveServiceId);
127131
if (service != null) {
128132
service.store(item, getAlias(item, effectiveServiceId));
133+
if (manager != null) {
134+
manager.handleExternalPersistenceDataChange(service, item);
135+
}
129136
return;
130137
}
131138
LoggerFactory.getLogger(PersistenceExtensions.class)
@@ -165,6 +172,9 @@ private static void internalPersist(Item item, ZonedDateTime timestamp, State st
165172
PersistenceService service = getService(effectiveServiceId);
166173
if (service instanceof ModifiablePersistenceService modifiableService) {
167174
modifiableService.store(item, timestamp, state, getAlias(item, effectiveServiceId));
175+
if (manager != null) {
176+
manager.handleExternalPersistenceDataChange(service, item);
177+
}
168178
return;
169179
}
170180
LoggerFactory.getLogger(PersistenceExtensions.class)
@@ -240,11 +250,14 @@ private static void internalPersist(Item item, TimeSeries timeSeries, @Nullable
240250
if (service instanceof ModifiablePersistenceService modifiableService) {
241251
if (timeSeries.getPolicy() == TimeSeries.Policy.REPLACE) {
242252
internalRemoveAllStatesBetween(item, timeSeries.getBegin().atZone(timeZone),
243-
timeSeries.getEnd().atZone(timeZone), serviceId);
253+
timeSeries.getEnd().atZone(timeZone), modifiableService, getAlias(item, effectiveServiceId));
244254
}
245255
String alias = getAlias(item, effectiveServiceId);
246256
timeSeries.getStates()
247257
.forEach(s -> modifiableService.store(item, s.timestamp().atZone(timeZone), s.state(), alias));
258+
if (manager != null) {
259+
manager.handleExternalPersistenceDataChange(service, item);
260+
}
248261
return;
249262
}
250263
LoggerFactory.getLogger(PersistenceExtensions.class)
@@ -3385,37 +3398,44 @@ private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDat
33853398
}
33863399
PersistenceService service = getService(effectiveServiceId);
33873400
if (service instanceof ModifiablePersistenceService mService) {
3388-
FilterCriteria filter = new FilterCriteria();
3389-
ZonedDateTime now = ZonedDateTime.now();
3390-
if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now))
3391-
|| (begin == null && end != null && end.isBefore(now))) {
3392-
LoggerFactory.getLogger(PersistenceExtensions.class).warn(
3393-
"Querying persistence service with open begin and/or end not allowed: begin {}, end {}, now {}",
3394-
begin, end, now);
3395-
return;
3396-
}
3397-
if (begin != null) {
3398-
filter.setBeginDate(begin);
3399-
} else {
3400-
filter.setBeginDate(now);
3401-
}
3402-
if (end != null) {
3403-
filter.setEndDate(end);
3404-
} else {
3405-
filter.setEndDate(now);
3401+
internalRemoveAllStatesBetween(item, begin, end, mService, getAlias(item, effectiveServiceId));
3402+
if (manager != null) {
3403+
manager.handleExternalPersistenceDataChange(mService, item);
34063404
}
3407-
String alias = getAlias(item, effectiveServiceId);
3408-
filter.setItemName(item.getName());
3409-
filter.setOrdering(Ordering.ASCENDING);
3410-
3411-
mService.remove(filter, alias);
34123405
} else {
34133406
LoggerFactory.getLogger(PersistenceExtensions.class)
34143407
.warn("There is no modifiable persistence service registered with the id '{}'", effectiveServiceId);
34153408
}
34163409
return;
34173410
}
34183411

3412+
private static void internalRemoveAllStatesBetween(Item item, @Nullable ZonedDateTime begin,
3413+
@Nullable ZonedDateTime end, ModifiablePersistenceService mService, @Nullable String alias) {
3414+
FilterCriteria filter = new FilterCriteria();
3415+
ZonedDateTime now = ZonedDateTime.now();
3416+
if ((begin == null && end == null) || (begin != null && end == null && begin.isAfter(now))
3417+
|| (begin == null && end != null && end.isBefore(now))) {
3418+
LoggerFactory.getLogger(PersistenceExtensions.class).warn(
3419+
"Querying persistence service with open begin and/or end not allowed: begin {}, end {}, now {}",
3420+
begin, end, now);
3421+
return;
3422+
}
3423+
if (begin != null) {
3424+
filter.setBeginDate(begin);
3425+
} else {
3426+
filter.setBeginDate(now);
3427+
}
3428+
if (end != null) {
3429+
filter.setEndDate(end);
3430+
} else {
3431+
filter.setEndDate(now);
3432+
}
3433+
filter.setItemName(item.getName());
3434+
filter.setOrdering(Ordering.ASCENDING);
3435+
3436+
mService.remove(filter, alias);
3437+
}
3438+
34193439
private static @Nullable Iterable<HistoricItem> getAllStatesBetweenWithBoundaries(Item item,
34203440
@Nullable ZonedDateTime begin, @Nullable ZonedDateTime end, @Nullable String serviceId) {
34213441
Iterable<HistoricItem> betweenItems = internalGetAllStatesBetween(item, begin, end, serviceId);

0 commit comments

Comments
 (0)