Skip to content

Commit

Permalink
Implementation of memory persistence service.
Browse files Browse the repository at this point in the history
This persistence service is self-contained and allows to retain data without disk/storage access.
It can be also used for items which have high update frequency and might put unecessary load on storage.

Signed-off-by: Łukasz Dywicki <luke@code-house.org>
  • Loading branch information
splatch committed Feb 22, 2024
1 parent d962485 commit 8443516
Show file tree
Hide file tree
Showing 10 changed files with 773 additions and 0 deletions.
87 changes: 87 additions & 0 deletions bundles/org.connectorio.addons.persistence.memory/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
- Copyright (C) 2024-2024 ConnectorIO Sp. z o.o.
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- SPDX-License-Identifier: Apache-2.0
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.connectorio.addons</groupId>
<artifactId>bundles</artifactId>
<version>3.0.0-SNAPSHOT</version>
</parent>

<artifactId>org.connectorio.addons.persistence.memory</artifactId>
<packaging>bundle</packaging>

<name>ConnectorIO - Addons - Persistence - Memory</name>
<description>A memory persistence service.</description>

<dependencies>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.persistence</artifactId>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.config.xml</artifactId>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.core</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.service.component.annotations</artifactId>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
</dependency>
<dependency>
<groupId>org.connectorio.addons</groupId>
<artifactId>org.connectorio.addons.test</artifactId>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2024-2024 ConnectorIO Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.connectorio.addons.persistence.memory.internal;

import java.util.Comparator;
import java.util.Date;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.TreeSet;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MemoryBucket {

private final Logger logger = LoggerFactory.getLogger(MemoryBucket.class);

private final NavigableSet<MemoryEntry> entries = new TreeSet<>(
Comparator.comparing(MemoryEntry::getTimestamp)
);

private final Lock lock = new ReentrantLock();
private int limit;

public MemoryBucket(int limit) {
this.limit = limit;
}

public void append(MemoryEntry entry) {
apply(myself -> {
logger.trace("Inserted entry {}. Stored entries {}, limit {}", entry, entries.size(), limit);
myself.entries.add(entry);
});
}

public void truncate(int limit) {
this.limit = limit;

apply(myself -> {
while (myself.entries.size() > limit) {
MemoryEntry entry = myself.entries.pollFirst();
logger.trace("Removed bucket entry {} as it exceeds limit {}", entry, limit);
}
});
}

public Stream<MemoryEntry> entries() {
return entries.stream();
}

public void remove(MemoryEntry entry) {
apply(myself -> myself.entries.remove(entry));
}

public Integer getSize() {
return entries.size();
}

public Date getEarliest() {
return entries.isEmpty() ? null : Date.from(entries.first().getTimestamp().toInstant());
}

public Date getOldest() {
return entries.isEmpty() ? null : Date.from(entries.last().getTimestamp().toInstant());
}

public <X> X process(Function<MemoryBucket, X> function) {
lock.lock();
try {
return function.apply(this);
} finally {
lock.unlock();
}
}

private void apply(Consumer<MemoryBucket> consumer) {
lock.lock();
try {
consumer.accept(this);
} finally {
lock.unlock();
}
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MemoryBucket)) {
return false;
}
MemoryBucket bucket = (MemoryBucket) o;
return limit == bucket.limit && Objects.equals(entries, bucket.entries);
}

@Override
public int hashCode() {
return Objects.hash(entries, limit);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (C) 2024-2024 ConnectorIO Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.connectorio.addons.persistence.memory.internal;

import java.util.Date;
import org.openhab.core.persistence.PersistenceItemInfo;

public class MemoryBucketInfo implements PersistenceItemInfo {

private final String name;
private final Integer count;
private final Date earliest;
private final Date oldest;

public MemoryBucketInfo(String name, Integer count, Date earliest, Date oldest) {
this.name = name;
this.count = count;
this.earliest = earliest;
this.oldest = oldest;
}


@Override
public String getName() {
return name;
}

@Override
public Integer getCount() {
return count;
}

@Override
public Date getEarliest() {
return earliest;
}

@Override
public Date getLatest() {
return oldest;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (C) 2024-2024 ConnectorIO Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.connectorio.addons.persistence.memory.internal;

import java.time.ZonedDateTime;
import java.util.Objects;
import org.openhab.core.types.State;

public class MemoryEntry {

private final ZonedDateTime timestamp;
private final State state;

public MemoryEntry(ZonedDateTime timestamp, State state) {
this.timestamp = timestamp;
this.state = state;
}

public ZonedDateTime getTimestamp() {
return timestamp;
}

public State getState() {
return state;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MemoryEntry)) {
return false;
}
MemoryEntry that = (MemoryEntry) o;
return Objects.equals(getTimestamp(), that.getTimestamp()) && Objects.equals(
getState(), that.getState());
}

@Override
public int hashCode() {
return Objects.hash(getTimestamp(), getState());
}

public String toString() {
return "MemoryEntry [" + timestamp + "=" + state + "]";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2024-2024 ConnectorIO Sp. z o.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.connectorio.addons.persistence.memory.internal;

import java.time.ZonedDateTime;
import org.openhab.core.persistence.HistoricItem;
import org.openhab.core.types.State;

public class MemoryHistoricItem implements HistoricItem {
private final String name;
private final ZonedDateTime timestamp;
private final State state;

public MemoryHistoricItem(String name, ZonedDateTime timestamp, State state) {
this.name = name;
this.timestamp = timestamp;
this.state = state;
}

@Override
public String getName() {
return name;
}

@Override
public ZonedDateTime getTimestamp() {
return timestamp;
}

@Override
public State getState() {
return state;
}

}
Loading

0 comments on commit 8443516

Please sign in to comment.