Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,8 @@ public void store(Item item) {
@Override
public void store(Item item, @Nullable String alias) {
// Timestamp and capture state immediately as rest of the store is asynchronous (state might change in between)
ZonedDateTime time = ZonedDateTime.now();
ZonedDateTime lastStateUpdate = item.getLastStateUpdate();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it guaranteed by the core that this timestamp is updated when persistence is called?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. If it isn't mapdb would have been badly broken for a long time and that would be Bad. It would also be a bug in the core since state and update time should change together. (Some might argue that the applies-from time should be part of the state...)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm what do you think about this AI analysis?

https://claude.ai/share/009bca45-734b-4c29-9d25-eac0eba4291f

I was worried as so much of this happens asynchronously in corr

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a core bug to me. I'd guess the chances of one of the notify or event jobs getting scheduled, starting up and making "enough" progress before applyState sets the update time is pretty slim. But it does seem wrong.

See Core issue 5711 and PR#5712

ZonedDateTime time = (lastStateUpdate != null ? lastStateUpdate : ZonedDateTime.now());

logIfManyQueuedTasks();
if (!(item instanceof GenericItem)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.lang.reflect.InvocationTargetException;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -194,15 +195,17 @@ private static void addFilterbyItemAndTimeFilter(QueryEnhancedRequest.Builder qu
// No need to place time filter, but we do filter by partition
queryBuilder.queryConditional(QueryConditional.keyEqualTo(k -> k.partitionValue(partition)));
} else if (begin != null && end == null) {
queryBuilder.queryConditional(QueryConditional
.sortGreaterThan(k -> k.partitionValue(partition).sortValue(timeConverter.transformFrom(begin))));
queryBuilder.queryConditional(QueryConditional.sortGreaterThanOrEqualTo(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find!

k -> k.partitionValue(partition).sortValue(timeConverter.transformFrom(begin))));
} else if (begin == null && end != null) {
queryBuilder.queryConditional(QueryConditional
.sortLessThan(k -> k.partitionValue(partition).sortValue(timeConverter.transformFrom(end))));
queryBuilder.queryConditional(QueryConditional.sortLessThanOrEqualTo(
k -> k.partitionValue(partition).sortValue(timeConverter.transformFrom(end))));
} else if (begin != null && end != null) {
queryBuilder.queryConditional(QueryConditional.sortBetween(
k -> k.partitionValue(partition).sortValue(timeConverter.transformFrom(begin)),
k -> k.partitionValue(partition).sortValue(timeConverter.transformFrom(end))));
k -> k.partitionValue(partition)
.sortValue(timeConverter.transformFrom(begin.truncatedTo(ChronoUnit.MILLIS).minusNanos(1))),
k -> k.partitionValue(partition)
.sortValue(timeConverter.transformFrom(end.truncatedTo(ChronoUnit.MILLIS).plusNanos(1)))));
Comment on lines 204 to +208
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,12 @@ protected void assertIterableContainsItems(Iterable<HistoricItem> iterable, bool
}

assertStateEquals(getFirstItemState(), storedFirst.getState());
assertTrue(storedFirst.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
assertTrue(storedFirst.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
assertTrue(!storedFirst.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we instead have sleep (1ms) somewhere?

I think these tests are mainly asserting ordering. If everything would be equal, that would not expected either?

assertTrue(!storedFirst.getTimestamp().toInstant().isBefore(beforeStore.toInstant()));

assertStateEquals(getSecondItemState(), storedSecond.getState());
assertTrue(storedSecond.getTimestamp().toInstant().isBefore(afterStore2.toInstant()));
assertTrue(storedSecond.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
assertTrue(!storedSecond.getTimestamp().toInstant().isAfter(afterStore2.toInstant()));
assertTrue(!storedSecond.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
}

@Test
Expand Down Expand Up @@ -225,8 +225,8 @@ public void testQueryUsingNameAndStartAndEndWithNEQOperator() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getFirstItemState(), actual1.getState());
assertTrue(actual1.getInstant().isBefore(afterStore1.toInstant()));
assertTrue(actual1.getInstant().isAfter(beforeStore.toInstant()));
assertTrue(!actual1.getInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getInstant().isBefore(beforeStore.toInstant()));
});
}

Expand All @@ -246,8 +246,8 @@ public void testQueryUsingNameAndStartAndEndWithEQOperator() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getFirstItemState(), actual1.getState());
assertTrue(actual1.getInstant().isBefore(afterStore1.toInstant()));
assertTrue(actual1.getInstant().isAfter(beforeStore.toInstant()));
assertTrue(!actual1.getInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getInstant().isBefore(beforeStore.toInstant()));
});
}

Expand All @@ -267,8 +267,8 @@ public void testQueryUsingNameAndStartAndEndWithLTOperator() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getFirstItemState(), actual1.getState());
assertTrue(actual1.getInstant().isBefore(afterStore1.toInstant()));
assertTrue(actual1.getInstant().isAfter(beforeStore.toInstant()));
assertTrue(!actual1.getInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getInstant().isBefore(beforeStore.toInstant()));
});
}

Expand Down Expand Up @@ -304,8 +304,8 @@ public void testQueryUsingNameAndStartAndEndWithLTEOperator() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getFirstItemState(), actual1.getState());
assertTrue(actual1.getInstant().isBefore(afterStore1.toInstant()));
assertTrue(actual1.getInstant().isAfter(beforeStore.toInstant()));
assertTrue(!actual1.getInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getInstant().isBefore(beforeStore.toInstant()));
});
}

Expand All @@ -331,8 +331,8 @@ public void testQueryUsingNameAndStartAndEndWithGTOperator() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getSecondItemState(), actual1.getState());
assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore2.toInstant()));
assertTrue(actual1.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getTimestamp().toInstant().isAfter(afterStore2.toInstant()));
assertTrue(!actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
});
}

Expand Down Expand Up @@ -368,8 +368,8 @@ public void testQueryUsingNameAndStartAndEndWithGTEOperator() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getSecondItemState(), actual1.getState());
assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore2.toInstant()));
assertTrue(actual1.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getTimestamp().toInstant().isAfter(afterStore2.toInstant()));
assertTrue(!actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
});
}

Expand All @@ -389,8 +389,8 @@ public void testQueryUsingNameAndStartAndEndFirst() {
HistoricItem actual1 = iterator.next();
assertFalse(iterator.hasNext());
assertStateEquals(getFirstItemState(), actual1.getState());
assertTrue(actual1.getTimestamp().toInstant().isBefore(afterStore1.toInstant()));
assertTrue(actual1.getTimestamp().toInstant().isAfter(beforeStore.toInstant()));
assertTrue(!actual1.getTimestamp().toInstant().isAfter(afterStore1.toInstant()));
assertTrue(!actual1.getTimestamp().toInstant().isBefore(beforeStore.toInstant()));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -43,16 +44,17 @@ public class CallItemIntegrationTest extends AbstractTwoItemIntegrationTest {
@BeforeAll
public static void storeData() throws InterruptedException {
CallItem item = (CallItem) ITEMS.get(NAME);
beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);
beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);

LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -54,16 +55,17 @@ private static HSBType color(String hue, int saturation, int brightness) {
@BeforeAll
public static void storeData() throws InterruptedException {
ColorItem item = (ColorItem) ITEMS.get(NAME);
beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);
beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);

LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.persistence.dynamodb.internal;

import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -41,16 +42,17 @@ public class ContactItemIntegrationTest extends AbstractTwoItemIntegrationTest {
@BeforeAll
public static void storeData() throws InterruptedException {
ContactItem item = (ContactItem) ITEMS.get(NAME);
beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);
beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);

LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -47,17 +48,17 @@ public class DateTimeItemIntegrationTest extends AbstractTwoItemIntegrationTest
public static void storeData() throws InterruptedException {
DateTimeItem item = (DateTimeItem) ITEMS.get(NAME);

beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);

beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.persistence.dynamodb.internal;

import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -40,17 +41,17 @@ public class DimmerItemIntegrationTest extends AbstractTwoItemIntegrationTest {
public static void storeData() throws InterruptedException {
DimmerItem item = (DimmerItem) ITEMS.get(NAME);

beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);

beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.persistence.dynamodb.internal;

import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -43,16 +44,17 @@ public class LocationItemIntegrationTest extends AbstractTwoItemIntegrationTest
@BeforeAll
public static void storeData() throws InterruptedException {
LocationItem item = (LocationItem) ITEMS.get(NAME);
beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);
beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);

LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -45,17 +46,17 @@ public class NumberItemIntegrationTest extends AbstractTwoItemIntegrationTest {
public static void storeData() throws InterruptedException {
NumberItem item = (NumberItem) ITEMS.get(NAME);

beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);

beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);

LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -49,7 +50,11 @@ public class PagingIntegrationTest extends BaseIntegrationTest {
@SuppressWarnings("null")
@BeforeAll
public static void populateData() {
storeStart = ZonedDateTime.now();
storeStart = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
}
Comment on lines +54 to +57

NumberItem item = (NumberItem) ITEMS.get(NAME);
for (int i = 0; i < STATE_COUNT; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package org.openhab.persistence.dynamodb.internal;

import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -40,17 +41,17 @@ public class PlayerItemPlayPauseIntegrationTest extends AbstractTwoItemIntegrati
public static void storeData() throws InterruptedException {
PlayerItem item = (PlayerItem) ITEMS.get(NAME);

beforeStore = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(1);
item.setState(STATE1);

beforeStore = ZonedDateTime.now();
Thread.sleep(10);
service.store(item);
afterStore1 = ZonedDateTime.now();
afterStore1 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);
Thread.sleep(10);
item.setState(STATE2);
service.store(item);
Thread.sleep(10);
afterStore2 = ZonedDateTime.now();
afterStore2 = ZonedDateTime.now().truncatedTo(ChronoUnit.MILLIS);

LOGGER.info("Created item between {} and {}", AbstractDynamoDBItem.DATEFORMATTER.format(beforeStore),
AbstractDynamoDBItem.DATEFORMATTER.format(afterStore1));
Expand Down
Loading
Loading